]> git.proxmox.com Git - ceph.git/blob - ceph/doc/radosgw/STS.rst
import quincy beta 17.1.0
[ceph.git] / ceph / doc / radosgw / STS.rst
1 ===========
2 STS in Ceph
3 ===========
4
5 Secure Token Service is a web service in AWS that returns a set of temporary security credentials for authenticating federated users.
6 The link to official AWS documentation can be found here: https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html.
7
8 Ceph Object Gateway implements a subset of STS APIs that provide temporary credentials for identity and access management.
9 These temporary credentials can be used to make subsequent S3 calls which will be authenticated by the STS engine in Ceph Object Gateway.
10 Permissions of the temporary credentials can be further restricted via an IAM policy passed as a parameter to the STS APIs.
11
12 STS REST APIs
13 =============
14
15 The following STS REST APIs have been implemented in Ceph Object Gateway:
16
17 1. AssumeRole: Returns a set of temporary credentials that can be used for
18 cross-account access. The temporary credentials will have permissions that are
19 allowed by both - permission policies attached with the Role and policy attached
20 with the AssumeRole API.
21
22 Parameters:
23 **RoleArn** (String/ Required): ARN of the Role to Assume.
24
25 **RoleSessionName** (String/ Required): An Identifier for the assumed role
26 session.
27
28 **Policy** (String/ Optional): An IAM Policy in JSON format.
29
30 **DurationSeconds** (Integer/ Optional): The duration in seconds of the session.
31 Its default value is 3600.
32
33 **ExternalId** (String/ Optional): A unique Id that might be used when a role is
34 assumed in another account.
35
36 **SerialNumber** (String/ Optional): The Id number of the MFA device associated
37 with the user making the AssumeRole call.
38
39 **TokenCode** (String/ Optional): The value provided by the MFA device, if the
40 trust policy of the role being assumed requires MFA.
41
42 2. AssumeRoleWithWebIdentity: Returns a set of temporary credentials for users that
43 have been authenticated by a web/mobile app by an OpenID Connect /OAuth2.0 Identity Provider.
44 Currently Keycloak has been tested and integrated with RGW.
45
46 Parameters:
47 **RoleArn** (String/ Required): ARN of the Role to Assume.
48
49 **RoleSessionName** (String/ Required): An Identifier for the assumed role
50 session.
51
52 **Policy** (String/ Optional): An IAM Policy in JSON format.
53
54 **DurationSeconds** (Integer/ Optional): The duration in seconds of the session.
55 Its default value is 3600.
56
57 **ProviderId** (String/ Optional): Fully qualified host component of the domain name
58 of the IDP. Valid only for OAuth2.0 tokens (not for OpenID Connect tokens).
59
60 **WebIdentityToken** (String/ Required): The OpenID Connect/ OAuth2.0 token, which the
61 application gets in return after authenticating its user with an IDP.
62
63 Before invoking AssumeRoleWithWebIdentity, an OpenID Connect Provider entity (which the web application
64 authenticates with), needs to be created in RGW.
65
66 The trust between the IDP and the role is created by adding a condition to the role's trust policy, which
67 allows access only to applications which satisfy the given condition.
68 All claims of the JWT are supported in the condition of the role's trust policy.
69 An example of a policy that uses the 'aud' claim in the condition is of the form::
70
71 '''{"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>"}}}]}'''
72
73 The app_id in the condition above must match the 'aud' claim of the incoming token.
74
75 An example of a policy that uses the 'sub' claim in the condition is of the form::
76
77 "{\"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>\"\}\}\}\]\}"
78
79 Similarly, an example of a policy that uses 'azp' claim in the condition is of the form::
80
81 "{\"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>\"\}\}\}\]\}"
82
83 A shadow user is created corresponding to every federated user. The user id is derived from the 'sub' field of the incoming web token.
84 The user is created in a separate namespace - 'oidc' such that the user id doesn't clash with any other user ids in rgw. The format of the user id
85 is - <tenant>$<user-namespace>$<sub> where user-namespace is 'oidc' for users that authenticate with oidc providers.
86
87 RGW now supports Session tags that can be passed in the web token to AssumeRoleWithWebIdentity call. More information related to Session Tags can be found here
88 :doc:`session-tags`.
89
90 STS Configuration
91 =================
92
93 The following configurable options have to be added for STS integration::
94
95 [client.radosgw.gateway]
96 rgw sts key = {sts key for encrypting the session token}
97 rgw s3 auth use sts = true
98
99 Note: By default, STS and S3 APIs co-exist in the same namespace, and both S3
100 and STS APIs can be accessed via the same endpoint in Ceph Object Gateway.
101
102 Examples
103 ========
104
105 1. The following is an example of AssumeRole API call, which shows steps to create a role, assign a policy to it
106 (that allows access to S3 resources), assuming a role to get temporary credentials and accessing s3 resources using
107 those credentials. In this example, TESTER1 assumes a role created by TESTER, to access S3 resources owned by TESTER,
108 according to the permission policy attached to the role.
109
110 .. code-block:: python
111
112 import boto3
113
114 iam_client = boto3.client('iam',
115 aws_access_key_id=<access_key of TESTER>,
116 aws_secret_access_key=<secret_key of TESTER>,
117 endpoint_url=<IAM URL>,
118 region_name=''
119 )
120
121 policy_document = '''{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":["arn:aws:iam:::user/TESTER1"]},"Action":["sts:AssumeRole"]}]}'''
122
123 role_response = iam_client.create_role(
124 AssumeRolePolicyDocument=policy_document,
125 Path='/',
126 RoleName='S3Access',
127 )
128
129 role_policy = '''{"Version":"2012-10-17","Statement":{"Effect":"Allow","Action":"s3:*","Resource":"arn:aws:s3:::*"}}'''
130
131 response = iam_client.put_role_policy(
132 RoleName='S3Access',
133 PolicyName='Policy1',
134 PolicyDocument=role_policy
135 )
136
137 sts_client = boto3.client('sts',
138 aws_access_key_id=<access_key of TESTER1>,
139 aws_secret_access_key=<secret_key of TESTER1>,
140 endpoint_url=<STS URL>,
141 region_name='',
142 )
143
144 response = sts_client.assume_role(
145 RoleArn=role_response['Role']['Arn'],
146 RoleSessionName='Bob',
147 DurationSeconds=3600
148 )
149
150 s3client = boto3.client('s3',
151 aws_access_key_id = response['Credentials']['AccessKeyId'],
152 aws_secret_access_key = response['Credentials']['SecretAccessKey'],
153 aws_session_token = response['Credentials']['SessionToken'],
154 endpoint_url=<S3 URL>,
155 region_name='',)
156
157 bucket_name = 'my-bucket'
158 s3bucket = s3client.create_bucket(Bucket=bucket_name)
159 resp = s3client.list_buckets()
160
161 2. The following is an example of AssumeRoleWithWebIdentity API call, where an external app that has users authenticated with
162 an OpenID Connect/ OAuth2 IDP (Keycloak in this example), assumes a role to get back temporary credentials and access S3 resources
163 according to permission policy of the role.
164
165 .. code-block:: python
166
167 import boto3
168
169 iam_client = boto3.client('iam',
170 aws_access_key_id=<access_key of TESTER>,
171 aws_secret_access_key=<secret_key of TESTER>,
172 endpoint_url=<IAM URL>,
173 region_name=''
174 )
175
176 oidc_response = iam_client.create_open_id_connect_provider(
177 Url=<URL of the OpenID Connect Provider,
178 ClientIDList=[
179 <Client id registered with the IDP>
180 ],
181 ThumbprintList=[
182 <Thumbprint of the IDP>
183 ]
184 )
185
186 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"}}}]}'''
187 role_response = iam_client.create_role(
188 AssumeRolePolicyDocument=policy_document,
189 Path='/',
190 RoleName='S3Access',
191 )
192
193 role_policy = '''{"Version":"2012-10-17","Statement":{"Effect":"Allow","Action":"s3:*","Resource":"arn:aws:s3:::*"}}'''
194
195 response = iam_client.put_role_policy(
196 RoleName='S3Access',
197 PolicyName='Policy1',
198 PolicyDocument=role_policy
199 )
200
201 sts_client = boto3.client('sts',
202 aws_access_key_id=<access_key of TESTER1>,
203 aws_secret_access_key=<secret_key of TESTER1>,
204 endpoint_url=<STS URL>,
205 region_name='',
206 )
207
208 response = client.assume_role_with_web_identity(
209 RoleArn=role_response['Role']['Arn'],
210 RoleSessionName='Bob',
211 DurationSeconds=3600,
212 WebIdentityToken=<Web Token>
213 )
214
215 s3client = boto3.client('s3',
216 aws_access_key_id = response['Credentials']['AccessKeyId'],
217 aws_secret_access_key = response['Credentials']['SecretAccessKey'],
218 aws_session_token = response['Credentials']['SessionToken'],
219 endpoint_url=<S3 URL>,
220 region_name='',)
221
222 bucket_name = 'my-bucket'
223 s3bucket = s3client.create_bucket(Bucket=bucket_name)
224 resp = s3client.list_buckets()
225
226 How to obtain thumbprint of an OpenID Connect Provider IDP
227 ==========================================================
228 1. Take the OpenID connect provider's URL and add /.well-known/openid-configuration
229 to it to get the URL to get the IDP's configuration document. For example, if the URL
230 of the IDP is http://localhost:8000/auth/realms/quickstart, then the URL to get the
231 document from is http://localhost:8000/auth/realms/quickstart/.well-known/openid-configuration
232
233 2. Use the following curl command to get the configuration document from the URL described
234 in step 1::
235
236 curl -k -v \
237 -X GET \
238 -H "Content-Type: application/x-www-form-urlencoded" \
239 "http://localhost:8000/auth/realms/quickstart/.well-known/openid-configuration" \
240 | jq .
241
242 3. From the response of step 2, use the value of "jwks_uri" to get the certificate of the IDP,
243 using the following code::
244 curl -k -v \
245 -X GET \
246 -H "Content-Type: application/x-www-form-urlencoded" \
247 "http://$KC_SERVER/$KC_CONTEXT/realms/$KC_REALM/protocol/openid-connect/certs" \
248 | jq .
249
250 3. Copy the result of "x5c" in the response above, in a file certificate.crt, and add
251 '-----BEGIN CERTIFICATE-----' at the beginning and "-----END CERTIFICATE-----"
252 at the end.
253
254 4. Use the following OpenSSL command to get the certificate thumbprint::
255
256 openssl x509 -in certificate.crt -fingerprint -noout
257
258 5. The result of the above command in step 4, will be a SHA1 fingerprint, like the following::
259
260 SHA1 Fingerprint=F7:D7:B3:51:5D:D0:D3:19:DD:21:9A:43:A9:EA:72:7A:D6:06:52:87
261
262 6. Remove the colons from the result above to get the final thumbprint which can be as input
263 while creating the OpenID Connect Provider entity in IAM::
264
265 F7D7B3515DD0D319DD219A43A9EA727AD6065287
266
267 Roles in RGW
268 ============
269
270 More information for role manipulation can be found here
271 :doc:`role`.
272
273 OpenID Connect Provider in RGW
274 ==============================
275
276 More information for OpenID Connect Provider entity manipulation
277 can be found here
278 :doc:`oidc`.
279
280 Keycloak integration with Radosgw
281 =================================
282
283 Steps for integrating Radosgw with Keycloak can be found here
284 :doc:`keycloak`.
285
286 STSLite
287 =======
288 STSLite has been built on STS, and documentation for the same can be found here
289 :doc:`STSLite`.