注意

本文档适用于 Ceph 开发版本。

Ceph中的STS

安全令牌服务(STS)是AWS中的一个网络服务,它返回一组临时安全凭证,用于对联合用户进行身份验证。https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html.

Ceph对象网关实现了STS API的一个子集,这些API提供临时凭证,用于身份和访问管理。

STS REST API

Ceph对象网关中实现了以下STS REST API:

  1. AssumeRole: 返回一组可用于跨账户访问的临时凭证。临时凭证的权限将由与角色关联的策略和与AssumeRole API关联的策略共同允许。

    参数:

    RoleArn(String/必需): 要假设的角色ARN。

    RoleSessionName(String/必需): 假设角色会话的标识符。

    Policy(String/可选): JSON格式的IAM策略。

    DurationSeconds(Integer/可选): 会话的持续时间(秒)。

    ExternalId(String/可选): 当角色在另一个账户中被假设时可能使用的唯一ID。

    SerialNumber(String/可选): 与进行AssumeRole调用用户关联的多因素认证(MFA)设备的ID。

    TokenCode(String/可选): 如果被假设的角色的信任策略需要MFA,则由MFA设备提供的值。

  2. AssumeRoleWithWebIdentity: 为通过OpenID Connect /OAuth2.0 身份提供者由网络/移动应用程序进行身份验证的用户返回一组临时凭证。

    参数:

    RoleArn(String/必需): 要假设的角色ARN。

    RoleSessionName(String/必需): 假设角色会话的标识符。

    Policy(String/可选): JSON格式的IAM策略。

    DurationSeconds(Integer/可选): 会话的持续时间(秒)。

    ProviderId(String/可选): IDP域名完全限定主机部分的域名。仅适用于OAuth2.0令牌(不适用于OpenID Connect令牌)。

    WebIdentityToken(String/必需): OpenID Connect/OAuth2.0令牌,应用程序在用IDP对其用户进行身份验证后获得。

在调用AssumeRoleWithWebIdentity之前,需要在RGW中为应用程序认证的OpenID Connect提供者实体创建一个实体。

IDP和角色之间的信任是通过向角色的信任策略添加条件来创建的,该条件仅允许满足给定条件的应用程序访问。

'''{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Federated":["arn:aws:iam:::oidc-provider/<URL of IDP>"]},"Action":["sts:AssumeRoleWithWebIdentity"],"Condition":{"StringEquals":{"<URL of IDP> :app_id":"<aud>"}}}]}'''

The app_id上述条件中的值必须与传入令牌的“aud”声明匹配。

使用条件中“sub”声明的策略示例的形式如下:

"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Federated\":[\"arn:aws:iam:::oidc-provider/<URL of IDP>\"]},\"Action\":[\"sts:AssumeRoleWithWebIdentity\"],\"Condition\":{\"StringEquals\":{\"<URL of IDP> :sub\":\"<sub>\"\}\}\}\]\}"

类似地,使用条件中“azp”声明的策略示例的形式如下:

"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Federated\":[\"arn:aws:iam:::oidc-provider/<URL of IDP>\"]},\"Action\":[\"sts:AssumeRoleWithWebIdentity\"],\"Condition\":{\"StringEquals\":{\"<URL of IDP> :azp\":\"<azp>\"\}\}\}\]\}"

每个联合用户都会创建一个对应的影子用户。用户ID是从传入的网页令牌的“sub”字段派生的。<tenant>$<user-namespace>$<sub>其中user-namespace对于使用oidc提供者进行身份验证的用户是“oidc”。

RGW现在支持会话标签,这些标签可以传递在Web令牌中到AssumeRoleWithWebIdentity调用。有关会话标签的更多信息可以在这里找到STS中基于属性的访问控制的会话标签.

STS配置

对于STS集成,需要添加以下可配置选项:

[client.{your-rgw-name}]
rgw_sts_key = {sts key for encrypting the session token}
rgw_s3_auth_use_sts = true

注意:

  • 默认情况下,STS和S3 API共存于同一命名空间,并且Ceph对象网关中的S3和STS API都可以通过同一端点访问。

  • The rgw_sts_key需要是一个由恰好16个字符组成的十六进制字符串。

示例

  1. 为了让示例正常工作,请确保用户TESTER拥有roles能力分配:

    radosgw-admin caps add --uid="TESTER" --caps="roles=*"
    
  2. 以下是一个AssumeRole API调用的示例,它显示了创建角色、向其分配策略(允许访问S3资源)、假设角色以获取临时凭证以及使用这些凭证访问S3资源的步骤。在这个示例中,TESTER1假设了TESTER创建的角色,以访问TESTER拥有的S3资源,

    import boto3
    
    iam_client = boto3.client('iam',
    aws_access_key_id=<access_key of TESTER>,
    aws_secret_access_key=<secret_key of TESTER>,
    endpoint_url=<IAM URL>,
    region_name=''
    )
    
    policy_document = '''{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["arn:aws:iam:::user/TESTER1"]},"Action":["sts:AssumeRole"]}]}'''
    
    role_response = iam_client.create_role(
    AssumeRolePolicyDocument=policy_document,
    Path='/',
    RoleName='S3Access',
    )
    
    role_policy = '''{"Version":"2012-10-17","Statement":{"Effect":"Allow","Action":"s3:*","Resource":"arn:aws:s3:::*"}}'''
    
    response = iam_client.put_role_policy(
    RoleName='S3Access',
    PolicyName='Policy1',
    PolicyDocument=role_policy
    )
    
    sts_client = boto3.client('sts',
    aws_access_key_id=<access_key of TESTER1>,
    aws_secret_access_key=<secret_key of TESTER1>,
    endpoint_url=<STS URL>,
    region_name='',
    )
    
    response = sts_client.assume_role(
    RoleArn=role_response['Role']['Arn'],
    RoleSessionName='Bob',
    DurationSeconds=3600
    )
    
    s3client = 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=<S3 URL>,
    region_name='',)
    
    bucket_name = 'my-bucket'
    s3bucket = s3client.create_bucket(Bucket=bucket_name)
    resp = s3client.list_buckets()
    
  3. 以下是一个AssumeRoleWithWebIdentity API调用的示例,其中有一个外部应用程序,该应用程序的用户通过OpenID Connect/OAuth IDP(本例中为Keycloak)进行身份验证,假设一个角色以获取临时凭证并根据角色的权限策略访问S3资源。

    import boto3
    
    iam_client = boto3.client('iam',
    aws_access_key_id=<access_key of TESTER>,
    aws_secret_access_key=<secret_key of TESTER>,
    endpoint_url=<IAM URL>,
    region_name=''
    )
    
    oidc_response = iam_client.create_open_id_connect_provider(
        Url=<URL of the OpenID Connect Provider,
        ClientIDList=[
            <Client id registered with the IDP>
        ],
        ThumbprintList=[
            <Thumbprint of the IDP>
     ]
    )
    
    policy_document = '''{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost:8080/auth/realms/demo"]},"Action":["sts:AssumeRoleWithWebIdentity"],"Condition":{"StringEquals":{"localhost:8080/auth/realms/demo:app_id":"customer-portal"}}}]}'''
    role_response = iam_client.create_role(
    AssumeRolePolicyDocument=policy_document,
    Path='/',
    RoleName='S3Access',
    )
    
    role_policy = '''{"Version":"2012-10-17","Statement":{"Effect":"Allow","Action":"s3:*","Resource":"arn:aws:s3:::*"}}'''
    
    response = iam_client.put_role_policy(
        RoleName='S3Access',
        PolicyName='Policy1',
        PolicyDocument=role_policy
    )
    
    sts_client = boto3.client('sts',
    aws_access_key_id=<access_key of TESTER1>,
    aws_secret_access_key=<secret_key of TESTER1>,
    endpoint_url=<STS URL>,
    region_name='',
    )
    
    response = client.assume_role_with_web_identity(
    RoleArn=role_response['Role']['Arn'],
    RoleSessionName='Bob',
    DurationSeconds=3600,
    WebIdentityToken=<Web Token>
    )
    
    s3client = 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=<S3 URL>,
    region_name='',)
    
    bucket_name = 'my-bucket'
    s3bucket = s3client.create_bucket(Bucket=bucket_name)
    resp = s3client.list_buckets()
    

如何获取OpenID Connect提供者IDP的指纹

  1. 取OpenID connect提供者的URL并在其后添加/.well-known/openid-configuration以获取获取IDP配置文档的URL。例如,如果IDP的URL是http://localhost:8000/auth/realms/quickstart,则获取文档的URL是http://localhost:8000/auth/realms/quickstart/.well-known/openid-configuration

  2. 使用以下curl命令从步骤1中描述的URL获取配置文档:

    curl -k -v \
      -X GET \
      -H "Content-Type: application/x-www-form-urlencoded" \
      "http://localhost:8000/auth/realms/quickstart/.well-known/openid-configuration" \
    | jq .
    
  3. 从步骤2的响应中,使用“jwks_uri”的值来获取IDP的证书,使用以下代码:

    curl -k -v \
     -X GET \
     -H "Content-Type: application/x-www-form-urlencoded" \
     "http://$KC_SERVER/$KC_CONTEXT/realms/$KC_REALM/protocol/openid-connect/certs" \
    | jq .
    
  4. 将上述响应中x5c的结果复制到一个文件certificate.crt,并在其开头添加-----BEGIN CERTIFICATE-----并在其末尾添加-----END CERTIFICATE-----

  5. 使用以下OpenSSL命令获取证书指纹:

    openssl x509 -in certificate.crt -fingerprint -noout
    
  6. 上述步骤5的命令结果将是一个SHA1指纹,如下所示:

    SHA1 Fingerprint=F7:D7:B3:51:5D:D0:D3:19:DD:21:9A:43:A9:EA:72:7A:D6:06:52:87
    
  7. 从上述结果中删除冒号以获取最终的指纹,该指纹可以在创建IAM中的OpenID Connect提供者实体时作为输入:

    F7D7B3515DD0D319DD219A43A9EA727AD6065287
    

RGW中的角色

更多关于角色操作的信息可以在这里找到Role.

RGW中的OpenID Connect提供者

更多关于OpenID Connect提供者实体操作的信息可以在这里找到RGW中的OpenID Connect提供者.

RGW与Keycloak的集成

集成RGW与Keycloak的步骤可以在这里找到将 Keycloak 与 RadosGW 集成.

STSLite

STSLite基于STS构建,相关文档可以在这里找到STS Lite.

由 Ceph 基金会带给您

Ceph 文档是一个社区资源,由非盈利的 Ceph 基金会资助和托管Ceph Foundation. 如果您想支持这一点和我们的其他工作,请考虑加入现在加入.