注意
本文档适用于 Ceph 的开发版本。
STS 中基于属性的访问控制的会话标签
会话标签是键值对,可以在联合用户时传递(目前仅支持作为传递给 AssumeRoleWithWebIdentity 的 web 令牌的一部分)。会话标签作为 aws:PrincipalTag 随 STS 返回的会话凭证(临时凭证)一起传递。这些 Principal Tags 包括作为 web 令牌一部分传入的会话标签以及附加到所假定角色的标签。请注意,标签必须始终在以下命名空间中指定:https://aws.amazon.com/tags。
以下是 IDP 在 web 令牌中传入的会话标签示例
{
"jti": "947960a3-7e91-4027-99f6-da719b0d4059",
"exp": 1627438044,
"nbf": 0,
"iat": 1627402044,
"iss": "https://:8080/auth/realms/quickstart",
"aud": "app-profile-jsp",
"sub": "test",
"typ": "ID",
"azp": "app-profile-jsp",
"auth_time": 0,
"session_state": "3a46e3e7-d198-4a64-8b51-69682bcfc670",
"preferred_username": "test",
"email_verified": false,
"acr": "1",
"https://aws.amazon.com/tags": [
{
"principal_tags": {
"Department": [
"Engineering",
"Marketing"
]
}
}
],
"client_id": "app-profile-jsp",
"username": "test",
"active": true
}
在 web 令牌中配置 Keycloak 以传递标签的步骤如下所述:将 Keycloak 与 RadosGW 集成。
如果联合用户传入的 web 令牌包含会话标签,则信任策略必须具有“sts:TagSession”权限,否则 AssumeRoleWithWebIdentity 操作将失败。以下是包含 sts:TagSession 的信任策略示例
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["sts:AssumeRoleWithWebIdentity","sts:TagSession"],
"Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/quickstart"]},
"Condition":{"StringEquals":{"localhost:8080/auth/realms/quickstart:sub":"test"}}
}]
}
标签键
以下是可用于角色的信任策略或角色的权限策略中的标签键
1. aws:RequestTag:此键用于将请求中传入的键值对与角色的信任策略中的键值对进行比较。在 AssumeRoleWithWebIdentity 的情况下,IDP 在 web 令牌中传入的会话标签可用作角色的信任策略中的 aws:RequestTag,基于此可以允许联合用户假定角色。
以下是使用 aws:RequestTag 的角色信任策略示例
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["sts:AssumeRoleWithWebIdentity","sts:TagSession"],
"Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/quickstart"]},
"Condition":{"StringEquals":{"aws:RequestTag/Department":"Engineering"}}
}]
}
2. aws:PrincipalTag:此键用于将附加到主体的键值对与策略中的键值对进行比较。在 AssumeRoleWithWebIdentity 的情况下,一旦用户经过身份验证,IDP 在 web 令牌中传入的会话标签将显示为临时凭证中的 Principal 标签,这些标签可用作角色的权限策略中的 aws:PrincipalTag。
以下是使用 aws:PrincipalTag 的角色权限策略示例
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["s3:*"],
"Resource":["arn:aws:s3::t1tenant:my-test-bucket","arn:aws:s3::t1tenant:my-test-bucket/*"],
"Condition":{"StringEquals":{"aws:PrincipalTag/Department":"Engineering"}}
}]
}
3. iam:ResourceTag:此键用于将附加到资源的键值对与策略中的键值对进行比较。在 AssumeRoleWithWebIdentity 的情况下,附加到角色的标签可用于与信任策略中的标签进行比较,以允许用户假定角色。RGW 现在支持对角色执行标记、列出标签和取消标记操作的 REST API。有关角色标记的更多信息,请参阅此处 角色。
以下是使用 aws:ResourceTag 的角色的信任策略示例
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["sts:AssumeRoleWithWebIdentity","sts:TagSession"],
"Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/quickstart"]},
"Condition":{"StringEquals":{"iam:ResourceTag/Department":"Engineering"}}
}]
}
要使上述功能起作用,您需要将“Department=Engineering”标签附加到角色。
4. aws:TagKeys:此键用于将请求中的标签与策略中的标签进行比较。在 AssumeRoleWithWebIdentity 的情况下,这可用于在允许用户假定角色之前检查角色的信任策略中的标签键。这也可以用于角色的权限策略中。
以下是使用 aws:TagKeys 的角色的信任策略示例
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["sts:AssumeRoleWithWebIdentity","sts:TagSession"],
"Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/quickstart"]},
"Condition":{"ForAllValues:StringEquals":{"aws:TagKeys":["Department"]}}
}]
}
“ForAllValues:StringEquals”测试请求中的每个标签键是否都是策略中标签键的子集。因此,上述条件限制了请求中传入的标签键。
5. s3:ResourceTag:此键用于将 s3 资源(存储桶或对象)上存在的标签与角色的权限策略中的标签进行比较。
以下是使用 s3:ResourceTag 的角色的权限策略示例
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["s3:PutBucketTagging"],
"Resource":["arn:aws:s3::t1tenant:my-test-bucket\","arn:aws:s3::t1tenant:my-test-bucket/*"]
},
{
"Effect":"Allow",
"Action":["s3:*"],
"Resource":["*"],
"Condition":{"StringEquals":{"s3:ResourceTag/Department":\"Engineering"}}
}
}
要使上述功能起作用,您需要将“Department=Engineering”标签附加到要应用此策略的存储桶(以及对象)上。
使用标签的策略的更多示例
1. 通过将传入请求中的标签与附加到角色的标签匹配来假定角色。aws:RequestTag 是 JWT(访问令牌)中的传入标签,iam:ResourceTag 是附加到所假定角色的标签
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["sts:AssumeRoleWithWebIdentity","sts:TagSession"],
"Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/quickstart"]},
"Condition":{"StringEquals":{"aws:RequestTag/Department":"${iam:ResourceTag/Department}"}}
}]
}
2. 通过将主体标签与 s3 资源标签匹配来评估角色的权限策略。aws:PrincipalTag 是随临时凭证一起传入的标签,s3:ResourceTag 是附加到 s3 资源(对象/存储桶)的标签
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["s3:PutBucketTagging"],
"Resource":["arn:aws:s3::t1tenant:my-test-bucket\","arn:aws:s3::t1tenant:my-test-bucket/*"]
},
{
"Effect":"Allow",
"Action":["s3:*"],
"Resource":["*"],
"Condition":{"StringEquals":{"s3:ResourceTag/Department":"${aws:PrincipalTag/Department}"}}
}
}
会话标签的属性
会话标签可以是多值的。(多值会话标签在 AWS 中不受支持)
IDP 最多允许传入 50 个会话标签。
允许的最大键大小为 128 个字符。
允许的最大值大小为 256 个字符。
标签或值不能以“aws:”开头。
s3 资源标签
如上所述,“s3:ResourceTag”键可用于在 RGW 中授权 s3 操作(这在 AWS 中是不允许的)。
s3:ResourceTag 是一个键,用于引用已附加到对象或存储桶的标签。可以使用可用的 REST API 将标签附加到对象或存储桶。
下表显示了哪些 s3 资源标签类型(存储桶/对象)支持授权特定操作。
操作 |
标签类型 |
|---|---|
GetObject GetObjectTags DeleteObjectTags DeleteObject PutACLs InitMultipart AbortMultipart ListMultipart GetAttrs PutObjectRetention GetObjectRetention PutObjectLegalHold GetObjectLegalHold |
对象标签 |
PutObjectTags GetBucketTags PutBucketTags DeleteBucketTags GetBucketReplication DeleteBucketReplication GetBucketVersioning SetBucketVersioning GetBucketWebsite SetBucketWebsite DeleteBucketWebsite StatBucket ListBucket GetBucketLogging GetBucketLocation DeleteBucket GetLC PutLC DeleteLC GetCORS PutCORS GetRequestPayment SetRequestPayment PutBucketPolicy GetBucketPolicy DeleteBucketPolicy PutBucketObjectLock GetBucketObjectLock GetBucketPolicyStatus PutBucketPublicAccessBlock GetBucketPublicAccessBlock DeleteBucketPublicAccessBlock |
存储桶标签 |
GetACLs PutACLs |
存储桶 ACL 的存储桶标签 对象 ACL 的对象标签 |
PutObject CopyObject |
源对象的对象标签 目标存储桶的存储桶标签 |
演示会话标签用法的示例代码
以下是用于标记角色、存储桶、其中的对象以及在角色的信任策略及其权限策略中使用标签键的示例代码,假设 IDP 在 JWT(访问令牌)中传入了标签“Department=Engineering”
# -*- coding: utf-8 -*-
import boto3
import json
from nose.tools import eq_ as eq
access_key = 'TESTER'
secret_key = 'test123'
endpoint = 'http://s3.us-east.localhost:8000'
s3client = boto3.client('s3',
aws_access_key_id = access_key,
aws_secret_access_key = secret_key,
endpoint_url = endpoint,
region_name='',)
s3res = boto3.resource('s3',
aws_access_key_id = access_key,
aws_secret_access_key = secret_key,
endpoint_url = endpoint,
region_name='',)
iam_client = boto3.client('iam',
aws_access_key_id=access_key,
aws_secret_access_key=secret_key,
endpoint_url=endpoint,
region_name=''
)
bucket_name = 'test-bucket'
s3bucket = s3client.create_bucket(Bucket=bucket_name)
bucket_tagging = s3res.BucketTagging(bucket_name)
Set_Tag = bucket_tagging.put(Tagging={'TagSet':[{'Key':'Department', 'Value': 'Engineering'}]})
try:
response = iam_client.create_open_id_connect_provider(
Url='https://:8080/auth/realms/quickstart',
ClientIDList=[
'app-profile-jsp',
'app-jee-jsp'
],
ThumbprintList=[
'F7D7B3515DD0D319DD219A43A9EA727AD6065287'
]
)
except ClientError as e:
print ("Provider already exists")
policy_document = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Federated\":[\"arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/quickstart\"]},\"Action\":[\"sts:AssumeRoleWithWebIdentity\",\"sts:TagSession\"],\"Condition\":{\"StringEquals\":{\"aws:RequestTag/Department\":\"${iam:ResourceTag/Department}\"}}}]}"
role_response = ""
print ("\n Getting Role \n")
try:
role_response = iam_client.get_role(
RoleName='S3Access'
)
print (role_response)
except ClientError as e:
if e.response['Code'] == 'NoSuchEntity':
print ("\n Creating Role \n")
tags_list = [
{'Key':'Department','Value':'Engineering'},
]
role_response = iam_client.create_role(
AssumeRolePolicyDocument=policy_document,
Path='/',
RoleName='S3Access',
Tags=tags_list,
)
print (role_response)
else:
print("Unexpected error: %s" % e)
role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":{\"Effect\":\"Allow\",\"Action\":\"s3:*\",\"Resource\":\"arn:aws:s3:::*\",\"Condition\":{\"StringEquals\":{\"s3:ResourceTag/Department\":[\"${aws:PrincipalTag/Department}\"]}}}}"
response = iam_client.put_role_policy(
RoleName='S3Access',
PolicyName='Policy1',
PolicyDocument=role_policy
)
sts_client = boto3.client('sts',
aws_access_key_id='abc',
aws_secret_access_key='def',
endpoint_url = endpoint,
region_name = '',
)
print ("\n Assuming Role with Web Identity\n")
response = sts_client.assume_role_with_web_identity(
RoleArn=role_response['Role']['Arn'],
RoleSessionName='Bob',
DurationSeconds=900,
WebIdentityToken='<web-token>')
s3client2 = boto3.client('s3',
aws_access_key_id = response['Credentials']['AccessKeyId'],
aws_secret_access_key = response['Credentials']['SecretAccessKey'],
aws_session_token = response['Credentials']['SessionToken'],
endpoint_url='http://s3.us-east.localhost:8000',
region_name='',)
bucket_body = 'this is a test file'
tags = 'Department=Engineering'
key = "test-1.txt"
s3_put_obj = s3client2.put_object(Body=bucket_body, Bucket=bucket_name, Key=key, Tagging=tags)
eq(s3_put_obj['ResponseMetadata']['HTTPStatusCode'],200)
s3_get_obj = s3client2.get_object(Bucket=bucket_name, Key=key)
eq(s3_get_obj['ResponseMetadata']['HTTPStatusCode'],200)