From 83cb3a964650cbdb2f6a0c314dd3592872678c3e Mon Sep 17 00:00:00 2001 From: Pritha Srivastava Date: Wed, 4 Dec 2019 10:27:05 +0530 Subject: [PATCH] rgw: adding documentation for AssumeRoleWithWebIdentity. Signed-off-by: Pritha Srivastava --- doc/radosgw/STS.rst | 212 +++++++++++++++++++++++++++++++++++++++ doc/radosgw/STSLite.rst | 96 +++++++----------- doc/radosgw/index.rst | 2 + doc/radosgw/keycloak.rst | 56 +++++++++++ 4 files changed, 304 insertions(+), 62 deletions(-) create mode 100644 doc/radosgw/STS.rst create mode 100644 doc/radosgw/keycloak.rst diff --git a/doc/radosgw/STS.rst b/doc/radosgw/STS.rst new file mode 100644 index 00000000000..0fbe41d34f1 --- /dev/null +++ b/doc/radosgw/STS.rst @@ -0,0 +1,212 @@ +=========== +STS in Ceph +=========== + +Secure Token Service is a web service in AWS that returns a set of temporary security credentials for authenticating federated users. +The link to official AWS documentation can be found here: https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html. + +Ceph Object Gateway implements a subset of STS APIs that provide temporary credentials for identity and access management. +These temporary credentials can be used to make subsequent S3 calls which will be authenticated by the STS engine in Ceph Object Gateway. +Permissions of the temporary credentials can be further restricted via an IAM policy passed as a parameter to the STS APIs. + +STS REST APIs +============= + +The following STS REST APIs have been implemented in Ceph Object Gateway: + +1. AssumeRole: Returns a set of temporary credentials that can be used for +cross-account access. The temporary credentials will have permissions that are +allowed by both - permission policies attached with the Role and policy attached +with the AssumeRole API. + +Parameters: + **RoleArn** (String/ Required): ARN of the Role to Assume. + + **RoleSessionName** (String/ Required): An Identifier for the assumed role + session. + + **Policy** (String/ Optional): An IAM Policy in JSON format. + + **DurationSeconds** (Integer/ Optional): The duration in seconds of the session. + Its default value is 3600. + + **ExternalId** (String/ Optional): A unique Id that might be used when a role is + assumed in another account. + + **SerialNumber** (String/ Optional): The Id number of the MFA device associated + with the user making the AssumeRole call. + + **TokenCode** (String/ Optional): The value provided by the MFA device, if the + trust policy of the role being assumed requires MFA. + +2. AssumeRoleWithWebIdentity: Returns a set of temporary credentials for users that +have been authenticated by a web/mobile app by an OpenID Connect /OAuth2.0 Identity Provider. +Currently Keycloak has been tested and integrated with RGW. + +Parameters: + **RoleArn** (String/ Required): ARN of the Role to Assume. + + **RoleSessionName** (String/ Required): An Identifier for the assumed role + session. + + **Policy** (String/ Optional): An IAM Policy in JSON format. + + **DurationSeconds** (Integer/ Optional): The duration in seconds of the session. + Its default value is 3600. + + **ProviderId** (String/ Optional): Fully qualified host component of the domain name + of the IDP. Valid only for OAuth2.0 tokens (not for OpenID Connect tokens). + + **WebIdentityToken** (String/ Required): The OpenID Connect/ OAuth2.0 token, which the + application gets in return after authenticating its user with an IDP. + +STS Configuration +================= + +The following configurable options have to be added for STS integration:: + + [client.radosgw.gateway] + rgw sts key = {sts key for encrypting the session token} + rgw s3 auth use sts = true + +The following additional configurables have to be added to use Keycloak for +AssumeRoleWithWebIdentity calls:: + + [client.radosgw.gateway] + rgw_sts_token_introspection_url = {token introspection URL} + rgw_sts_client_id = {client id registered with Keycloak} + rgw_sts_client_secret = {client password registered with Keycloak} + +Note: By default, STS and S3 APIs co-exist in the same namespace, and both S3 +and STS APIs can be accessed via the same endpoint in Ceph Object Gateway. + +Examples +======== + +1. The following is an example of AssumeRole API call, which shows steps to create a role, assign a policy to it +(that allows access to S3 resources), assuming a role to get temporary credentials and accessing s3 resources using +those credentials. In this example, TESTER1 assumes a role created by TESTER, to access S3 resources owned by TESTER, +according to the permission policy attached to the role. + +.. code-block:: python + + import boto3 + + iam_client = boto3.client('iam', + aws_access_key_id=, + aws_secret_access_key=, + endpoint_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=, + aws_secret_access_key=, + endpoint_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=, + region_name='',) + + bucket_name = 'my-bucket' + s3bucket = s3client.create_bucket(Bucket=bucket_name) + resp = s3client.list_buckets() + +2. The following is an example of AssumeRoleWithWebIdentity API call, where an external app that has users authenticated with +an OpenID Connect/ OAuth2 IDP (Keycloak in this example), assumes a role to get back temporary credentials and access S3 resources +according to permission policy of the role. + +.. code-block:: python + + import boto3 + + iam_client = boto3.client('iam', + aws_access_key_id=, + aws_secret_access_key=, + endpoint_url=, + region_name='' + ) + + 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=, + aws_secret_access_key=, + endpoint_url=, + region_name='', + ) + + response = client.assume_role_with_web_identity( + RoleArn=role_response['Role']['Arn'], + RoleSessionName='Bob', + DurationSeconds=3600, + WebIdentityToken= + ) + + 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=, + region_name='',) + + bucket_name = 'my-bucket' + s3bucket = s3client.create_bucket(Bucket=bucket_name) + resp = s3client.list_buckets() + +Roles in RGW +============ + +More information for role manipulation can be found here +:doc:`role`. + +Keycloak integration with Radosgw +================================= + +Steps for integrating Radosgw with Keycloak can be found here +:doc:`keycloak`. + +STSLite +======= +STSLite has been built on STS, and documentation for the same can be found here +:doc:`STSLite`. \ No newline at end of file diff --git a/doc/radosgw/STSLite.rst b/doc/radosgw/STSLite.rst index cc34e305f85..350e36bc610 100644 --- a/doc/radosgw/STSLite.rst +++ b/doc/radosgw/STSLite.rst @@ -3,25 +3,26 @@ STS Lite ========= Ceph Object Gateway provides support for a subset of Amazon Secure Token Service -(STS) APIs. STS Lite provides access to a set of temporary credentials for -Identity and Access Management. +(STS) APIs. STS Lite is an extension of STS and builds upon one of its APIs to +decrease the load on external IDPs like Keystone and LDAP. -STS authentication mechanism has been integrated with Keystone in Ceph Object -Gateway. A set of temporary security credentials is returned after authenticating -a set of AWS credentials with Keystone. These temporary credentials can be used -to make subsequent S3 calls which will be authenticated by the STS engine, -resulting in less load on the Keystone server. +A set of temporary security credentials is returned after authenticating +a set of AWS credentials with the external IDP. These temporary credentials can be used +to make subsequent S3 calls which will be authenticated by the STS engine in Ceph, +resulting in less load on the Keystone/ LDAP server. + +Temporary and limited privileged credentials can be obtained for a local user +also using the STS Lite API. STS Lite REST APIs ================== -The following STS Lite REST APIs have been implemented in Ceph Object Gateway: +The following STS Lite REST API is part of STS Lite in Ceph Object Gateway: 1. GetSessionToken: Returns a set of temporary credentials for a set of AWS -credentials. This API can be used for initial authentication with Keystone -and the temporary credentials returned can be used to make subsequent S3 -calls. The temporary credentials will have the same permission as that of the -AWS credentials. +credentials. After initial authentication with Keystone/ LDAP, the temporary +credentials returned can be used to make subsequent S3 calls. The temporary +credentials will have the same permission as that of the AWS credentials. Parameters: **DurationSeconds** (Integer/ Optional): The duration in seconds for which the @@ -44,32 +45,6 @@ The user attaching the policy needs to have admin caps. For example:: radosgw-admin caps add --uid="TESTER" --caps="user-policy=*" -2. AssumeRole: Returns a set of temporary credentials that can be used for -cross-account access. The temporary credentials will have permissions that are -allowed by both - permission policies attached with the Role and policy attached -with the AssumeRole API. - -Parameters: - **RoleArn** (String/ Required): ARN of the Role to Assume. - - **RoleSessionName** (String/ Required): An Identifier for the assumed role - session. - - **Policy** (String/ Optional): An IAM Policy in JSON format. - - **DurationSeconds** (Integer/ Optional): The duration in seconds of the session. - Its default value is 3600. - - **ExternalId** (String/ Optional): A unique Id that might be used when a role is - assumed in another account. - - **SerialNumber** (String/ Optional): The Id number of the MFA device associated - with the user making the AssumeRole call. - - **TokenCode** (String/ Optional): The value provided by the MFA device, if the - trust policy of the role being assumed requires MFA. - - STS Lite Configuration ====================== @@ -99,6 +74,26 @@ configurable options will be:: rgw keystone token cache size = {number of tokens to cache} rgw s3 auth use keystone = true +The details of the integrating ldap with Ceph Object Gateway can be found here: +:doc:`keystone` + +The complete set of configurables to use STS Lite with LDAP are:: + + [client.radosgw.gateway] + rgw sts key = {sts key for encrypting/ decrypting the session token} + rgw s3 auth use sts = true + + rgw_s3_auth_use_ldap = true + rgw_ldap_uri = {LDAP server to use} + rgw_ldap_binddn = {Distinguished Name (DN) of the service account} + rgw_ldap_secret = {password for the service account} + rgw_ldap_searchdn = {base in the directory information tree for searching users} + rgw_ldap_dnattr = {attribute being used in the constructed search filter to match a username} + rgw_ldap_searchfilter = {search filter} + +The details of the integrating ldap with Ceph Object Gateway can be found here: +:doc:`ldap-auth` + Note: By default, STS and S3 APIs co-exist in the same namespace, and both S3 and STS APIs can be accessed via the same endpoint in Ceph Object Gateway. @@ -167,30 +162,7 @@ Keystone. created = bucket['CreationDate'], ) -4. The following is an example of AssumeRole API call: - -.. code-block:: python - - import boto3 - - access_key = - secret_key = - - client = boto3.client('sts', - aws_access_key_id=access_key, - aws_secret_access_key=secret_key, - endpoint_url=, - region_name='', - ) - - response = client.assume_role( - RoleArn='arn:aws:iam:::role/application_abc/component_xyz/S3Access', - RoleSessionName='Bob', - DurationSeconds=3600 - ) - - -Note: A role 'S3Access', needs to be created before calling the AssumeRole API. +Similar steps can be performed for using GetSessionToken with LDAP. Limitations and Workarounds =========================== diff --git a/doc/radosgw/index.rst b/doc/radosgw/index.rst index 22b882f3ed0..86957c5f765 100644 --- a/doc/radosgw/index.rst +++ b/doc/radosgw/index.rst @@ -64,7 +64,9 @@ you may write data with one API and retrieve it with the other. Sync Modules Bucket Notifications Data Layout in RADOS + STS STS Lite + Keycloak Role troubleshooting Manpage radosgw <../../man/8/radosgw> diff --git a/doc/radosgw/keycloak.rst b/doc/radosgw/keycloak.rst new file mode 100644 index 00000000000..b160c439bf8 --- /dev/null +++ b/doc/radosgw/keycloak.rst @@ -0,0 +1,56 @@ +================================= +Keycloak integration with RadosGW +================================= + +Keycloak can be setup as an OpenID Connect Identity Provider, which can be used by mobile/ web apps +to authenticate their users. The Web token returned as a result of authentication can be used by the +mobile/ web app to call AssumeRoleWithWebIdentity to get back a set of temporary S3 credentials, +which can be used by the app to make S3 calls. + +Setting up Keycloak +==================== + +Installing and bringing up Keycloak can be found here: https://www.keycloak.org/docs/latest/server_installation/. + +Configuring Keycloak to talk to RGW +=================================== + +The following configurables have to be added for RGW to talk to Keycloak. +The format of token inspection url is https://[base-server-url]/token/introspect:: + + [client.radosgw.gateway] + rgw sts key = {sts key for encrypting/ decrypting the session token} + rgw s3 auth use sts = true + rgw_sts_token_introspection_url = {url for token introspection} + rgw_sts_client_id = {client-id} + rgw_sts_client_secret = {client-password} + +Example showing how to fetch a web token from Keycloak +====================================================== + +Several examples of apps authenticating with Keycloak are given here: https://github.com/keycloak/keycloak/tree/master/examples/demo-template +Taking the example of customer-portal app given in the link above, its client secret and client password, can be used to fetch the +access token (web token) as given below:: + + KC_REALM=demo + KC_CLIENT=customer-portal + KC_CLIENT_SECRET=password + KC_SERVER=:8080 + KC_CONTEXT=auth + + # Request Tokens for credentials + KC_RESPONSE=$( \ + curl -k -v -X POST \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "scope=openid" \ + -d "grant_type=client_credentials" \ + -d "client_id=$KC_CLIENT" \ + -d "client_secret=$KC_CLIENT_SECRET" \ + "http://$KC_SERVER/$KC_CONTEXT/realms/$KC_REALM/protocol/openid-connect/token" \ + | jq . + ) + + KC_ACCESS_TOKEN=$(echo $KC_RESPONSE| jq -r .access_token) + +KC_ACCESS_TOKEN can be used to invoke AssumeRoleWithWebIdentity as given in +:doc:`STS`. -- 2.39.5