16 KiB
Policy converters
This repository contains converters that provide opportunities to transform AWS IAM policies to inner FrostFS policy format. This document describes such transformations.
FrostFS
As it was mentioned there are converters that transform AWS IAM policies to FrostFS. Here common examples of AWS:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "*"
}
]
}
and FrostFS:
{
"ID": "c29tZS1pZA==",
"Rules": [
{
"Status": "Allow",
"Actions": {
"Inverted": false,
"Names": [
"s3:*"
]
},
"Resources": {
"Inverted": false,
"Names": [
"*"
]
},
"Any": false,
"Condition": null
}
],
"MatchType": "DenyPriority"
}
policies.
Despite there is only one FrostFS format, we have two converters (s3
and native
). The reason is S3 gateway and
Storage node have different actions and resource naming:
- S3 has a lot of methods and operates with bucket/object
- Storage node has only 6 container and 7 object methods and operates container/object (that has different format)
The following sections describe each transformation more precisely (common sections contains shared concepts)
Common
Fields
Rough json main fields mapping:
AWS policy field | FrostFS policy field | Comment |
---|---|---|
Version |
- | Not applicable |
Statement |
Rules |
|
Effect |
Status |
|
Action |
Actions.Names |
Actions.Inverted = false |
NotAction |
Actions.Names |
Actions.Inverted = true |
Resource |
Resources.Names |
Resources.Inverted = false |
NotResource |
Resources.Names |
Resources.Inverted = true |
Condition |
Condition |
Any = false, that means the conditions must be hold altogether |
Principal |
- | Expressed via conditions (depends on s3/native converters) |
Conditions
Each condition in FrostFS policy can add requirements to some request/resource properties and consists of the following fields:
Field | Description |
---|---|
Op |
Condition type operation (StringEqual , NumericEqual etc) |
Object |
Property type to which condition can be applied (Request property, Resource property) |
Key |
Property key |
Value |
Property value |
Conditions operators:
AWS conditions operator | FrostFS condition operator | Comment |
---|---|---|
StringEquals |
StringEquals |
|
StringNotEquals |
StringNotEquals |
|
StringEqualsIgnoreCase |
StringEqualsIgnoreCase |
|
StringNotEqualsIgnoreCase |
StringNotEqualsIgnoreCase |
|
StringLike |
StringLike |
|
StringNotLike |
StringNotLike |
|
NumericEquals |
NumericEquals |
|
NumericNotEquals |
NumericNotEquals |
|
NumericLessThan |
NumericLessThan |
|
NumericLessThanEquals |
NumericLessThanEquals |
|
NumericGreaterThan |
NumericGreaterThan |
|
NumericGreaterThanEquals |
NumericGreaterThanEquals |
|
DateEquals |
StringEquals |
Date transforms to unix timestamp to be compared as string |
DateNotEquals |
StringNotEquals |
Date transforms to unix timestamp to be compared as string |
DateLessThan |
StringEqualsIgnoreCase |
Date transforms to unix timestamp to be compared as string |
DateLessThanEquals |
StringNotEqualsIgnoreCase |
Date transforms to unix timestamp to be compared as string |
DateGreaterThan |
StringLike |
Date transforms to unix timestamp to be compared as string |
DateGreaterThanEquals |
StringNotLike |
Date transforms to unix timestamp to be compared as string |
Bool |
StringEqualsIgnoreCase |
|
IpAddress |
IPAddress |
|
NotIpAddress |
NotIPAddress |
|
ArnEquals |
StringEquals |
|
ArnLike |
StringLike |
|
ArnNotEquals |
StringNotEquals |
|
ArnNotLike |
StringNotLike |
|
SliceContains |
SliceContains |
AWS spec doesn't contain such operator. This is FrostFS extension |
For example, AWS conditions:
{
"Condition": {
"ArnEquals": {"key16": ["val16"]},
"ArnNotEquals": {"key18": ["val18"]},
"ArnNotLike": {"key19": ["val19"]},
"Bool": {"key13": ["True"]},
"DateEquals": {"key7": ["2006-01-02T15:04:05+07:00"]},
"DateGreaterThan": {"key11": ["2006-01-02T15:04:05-01:00"]},
"DateGreaterThanEquals": {"key12": ["2006-01-02T15:04:05-03:00"]},
"DateLessThan": {"key9": ["2006-01-02T15:04:05+06:00"]},
"DateLessThanEquals": {"key10": ["2006-01-02T15:04:05+03:00"]},
"DateNotEquals": {"key8": ["2006-01-02T15:04:05Z"]},
"NumericEquals": {"key20": ["-20"]},
"NumericGreaterThan": {"key24": ["-24.24"]},
"NumericGreaterThanEquals": {"key25": ["+25.25"]},
"NumericLessThan": {"key22": ["0"]},
"NumericLessThanEquals": {"key23": ["23.23"]},
"NumericNotEquals": {"key21": ["+21"]},
"StringEquals": {"key1": ["val0"]},
"StringEqualsIgnoreCase": {"key3": ["val3"]},
"StringLike": {"key5": ["val5"]},
"StringNotEquals": {"key2": ["val2"]},
"StringNotEqualsIgnoreCase": {"key4": ["val4"]},
"StringNotLike": {"key6": ["val6"]}
}
}
transforms to FrostFS conditions:
{
"Condition": [
{"Op": "StringLike", "Object": "Request", "Key": "key5", "Value": "val5"},
{"Op": "StringNotEquals", "Object": "Request", "Key": "key2", "Value": "val2"},
{"Op": "StringGreaterThan", "Object": "Request", "Key": "key11", "Value": "1136217845"},
{"Op": "StringGreaterThanEquals", "Object": "Request", "Key": "key12", "Value": "1136225045"},
{"Op": "StringLessThan", "Object": "Request", "Key": "key9", "Value": "1136192645"},
{"Op": "StringEqualsIgnoreCase", "Object": "Request", "Key": "key3", "Value": "val3"},
{"Op": "StringEquals", "Object": "Request", "Key": "key16", "Value": "val16"},
{"Op": "NumericLessThanEquals", "Object": "Request", "Key": "key23", "Value": "23.23"},
{"Op": "StringNotEqualsIgnoreCase", "Object": "Request", "Key": "key4", "Value": "val4"},
{"Op": "StringEquals", "Object": "Request", "Key": "key1", "Value": "val0"},
{"Op": "StringLessThanEquals", "Object": "Request", "Key": "key10", "Value": "1136203445"},
{"Op": "NumericGreaterThan", "Object": "Request", "Key": "key24", "Value": "-24.24"},
{"Op": "NumericGreaterThanEquals", "Object": "Request", "Key": "key25", "Value": "+25.25"},
{"Op": "NumericLessThan", "Object": "Request", "Key": "key22", "Value": "0"},
{"Op": "StringNotEquals", "Object": "Request", "Key": "key8", "Value": "1136214245"},
{"Op": "NumericEquals", "Object": "Request", "Key": "key20", "Value": "-20"},
{"Op": "NumericNotEquals", "Object": "Request", "Key": "key21", "Value": "+21"},
{"Op": "StringNotLike", "Object": "Request", "Key": "key6", "Value": "val6"},
{"Op": "StringNotEquals", "Object": "Request", "Key": "key18", "Value": "val18"},
{"Op": "StringNotLike", "Object": "Request", "Key": "key19", "Value": "val19"},
{"Op": "StringEqualsIgnoreCase", "Object": "Request", "Key": "key13", "Value": "True"},
{"Op": "StringEquals", "Object": "Request", "Key": "key7", "Value": "1136189045"}
]
}
S3
Actions
Each action allows some s3-gw methods, so we must transform action to specific method names (you can see exact mapping in table in this file).
For example the following actions:
{
"Action": [
"s3:DeleteObject",
"iam:CreateUser"
]
}
transforms to
{
"Actions": {
"Inverted": false,
"Names": [
"s3:DeleteObject",
"s3:DeleteMultipleObjects",
"iam:CreateUser"
]
}
}
As we can see any iam:*
action transformed as it is. But s3:*
actions transforms according to
spec rules and s3-gw
method names.
Resources
Resource is transformed as it is:
{
"Resource": [
"arn:aws:s3:::bucket/object"
]
}
{
"Resources": {
"Inverted": false,
"Names": [
"arn:aws:s3:::bucket/object"
]
}
}
Principals
To check user s3-gw uses special condition request property (Owner
), so when AWS policy contains principal field
it transforms to rule with appropriate condition. To get correct Owner
property value special user resolver
(S3Resolver
interface in converter_s3 file) must be provided into convert function.
For example such AWS json statement:
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Principal": {
"AWS": "arn:aws:iam::111122223333:user/JohnDoe"
}
}
transforms to the following FrostFS rule:
{
"Status": "Allow",
"Actions": {
"Inverted": false,
"Names": [
"*"
]
},
"Resources": {
"Inverted": false,
"Names": [
"*"
]
},
"Any": false,
"Condition": [
{
"Op": "StringEquals",
"Object": "Request",
"Key": "Owner",
"Value": "NbUgTSFvPmsRxmGeWpuuGeJUoRoi6PErcM"
}
]
}
Native
Actions
Each action allows some frostfs methods, so we must transform action to specific method names (you can see exact mapping in table in this file).
For example the following actions:
{
"Action": [
"s3:DeleteObject",
"iam:CreateUser"
]
}
transforms to
{
"Actions": {
"Inverted": false,
"Names": [
"PutObject",
"HeadObject",
"GetObject",
"RangeObject",
"GetContainer",
"DeleteObject"
]
}
}
Note: Only subset of s3:* actions can be transformed (exact value you can see in mapping table mentioned before). If all provided actions is not applicable converter function returns appropriate error.
Native methods (to which original actions are transformed) depend on which methods are invoked by appropriate s3-gw method.
So in example above s3-gw during performing DeleteObject methods invokes the following methods:
["PutObject","HeadObject","GetObject","RangeObject","GetContainer","DeleteObject"]
Resources
To transform resources the following is being performed:
- Bucket name is resoled to container id (by providing
NativeResolver
interface implementation to converter) - Object name is transformed to condition with special
FilePath
attribute (that present on every object that was uploaded via s3-gw)
For example, the following AWS policy statement:
{
"Principal": "*",
"Effect": "Allow",
"Action": "*",
"Resource": "arn:aws:s3:::bucket/object"
}
transforms to FrostFS native policy rule:
{
"Status": "Allow",
"Actions": {
"Inverted": false,
"Names": [
"*"
]
},
"Resources": {
"Inverted": false,
"Names": [
"native:object//bucket/HFq67qbfhFEiEL7qDXqayo3F78yAvxXSXzwSa2hKM9bH/*",
"native:container//bucket/HFq67qbfhFEiEL7qDXqayo3F78yAvxXSXzwSa2hKM9bH"
]
},
"Any": false,
"Condition": [
{
"Op": "StringLike",
"Object": "Resource",
"Key": "FilePath",
"Value": "object"
}
]
}
Principals
To check user s3-gw uses special condition request property ($Actor:publicKey
), so when AWS policy contains principal
field it transforms to rule with appropriate condition. To get correct $Actor:publicKey
property value
special user resolver (NativeResolver
interface in converter_native file) must be
provided into convert function.
For example such AWS json statement:
{
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Principal": {
"AWS": "arn:aws:iam::111122223333:user/JohnDoe"
}
}
transforms to the following FrostFS rule:
{
"Status": "Allow",
"Actions": {
"Inverted": false,
"Names": [
"*"
]
},
"Resources": {
"Inverted": false,
"Names": [
"native:object/*",
"native:container/*"
]
},
"Any": false,
"Condition": [
{
"Op": "StringEquals",
"Object": "Request",
"Key": "$Actor:publicKey",
"Value": "031a6c6fbbdf02ca351745fa86b9ba5a9452d785ac4f7fc2b7548ca2a46c4fcf4a"
}
]
}