sigs.k8s.io/cluster-api-provider-aws@v1.5.5/docs/book/src/topics/multitenancy.md (about) 1 # Multi-tenancy 2 3 Starting from v0.6.5, single controller multi-tenancy is supported that allows using a different AWS Identity for each workload cluster. 4 For details, see the [multi-tenancy proposal](https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/main/docs/proposal/20200506-single-controller-multitenancy.md). 5 6 7 For multi-tenancy support, a reference field (`identityRef`) is added to `AWSCluster`, which informs the controller of which identity to be used when reconciling the cluster. 8 If the identity provided exists in a different AWS account, this is the mechanism which informs the controller to provision a cluster in a different account. 9 Identities should have adequate permissions for CAPA to reconcile clusters. 10 11 12 ```yaml 13 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 14 kind: AWSCluster 15 metadata: 16 name: "test" 17 namespace: "test" 18 spec: 19 region: "eu-west-1" 20 identityRef: 21 kind: <IdentityType> 22 name: <IdentityName> 23 ``` 24 25 Identity resources are used to describe IAM identities that will be used during reconciliation. 26 There are three identity types: AWSClusterControllerIdentity, AWSClusterStaticIdentity, and AWSClusterRoleIdentity. 27 Once an IAM identity is created in AWS, the corresponding values should be used to create a identity resource. 28 29 ## AWSClusterControllerIdentity 30 31 Before multi-tenancy support, all AWSClusters were being reconciled using the credentials that are used by Cluster API Provider AWS Controllers. 32 `AWSClusterControllerIdentity` is used to restrict the usage of controller credentials only to AWSClusters that are in `allowedNamespaces`. 33 Since CAPA controllers use a single set of credentials, `AWSClusterControllerIdentity` is a singleton, and can only be created with `name: default`. 34 35 For backward compatibility, `AutoControllerIdentityCreator` experimental feature is added, which is responsible to create the `AWSClusterControllerIdentity` singleton if it does not exist. 36 - **Feature status:** Experimental 37 - **Feature gate:** AutoControllerIdentityCreator=true 38 `AutoControllerIdentityCreator` creates `AWSClusterControllerIdentity` singleton with empty `allowedNamespaces` (allowedNamespaces: {}) to grant access to the `AWSClusterControllerIdentity` from all namespaces. 39 40 Example: 41 ```yaml 42 --- 43 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 44 kind: AWSCluster 45 metadata: 46 name: "test" 47 namespace: "test" 48 spec: 49 region: "eu-west-1" 50 identityRef: 51 kind: AWSClusterControllerIdentity 52 name: default 53 --- 54 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 55 kind: AWSClusterControllerIdentity 56 metadata: 57 name: "default" 58 spec: 59 allowedNamespaces:{} # matches all namespaces 60 ``` 61 `AWSClusterControllerIdentity` is immutable to avoid any unwanted overrides to the allowed namespaces, especially during upgrading clusters. 62 63 ## AWSClusterStaticIdentity 64 `AWSClusterStaticIdentity` represents static AWS credentials, which are stored in a `Secret`. 65 66 Example: Below, an `AWSClusterStaticIdentity` is created that allows access to the `AWSClusters` that are in "test" namespace. 67 The identity credentials that will be used by "test" AWSCluster are stored in "test-account-creds" secret. 68 69 70 ```yaml 71 --- 72 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 73 kind: AWSCluster 74 metadata: 75 name: "test" 76 namespace: "test" 77 spec: 78 region: "eu-west-1" 79 identityRef: 80 kind: AWSClusterStaticIdentity 81 name: test-account 82 --- 83 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 84 kind: AWSClusterStaticIdentity 85 metadata: 86 name: "test-account" 87 spec: 88 secretRef: 89 name: test-account-creds 90 namespace: capa-system 91 allowedNamespaces: 92 selector: 93 matchLabels: 94 cluster.x-k8s.io/ns: "testlabel" 95 --- 96 apiVersion: v1 97 kind: Namespace 98 metadata: 99 labels: 100 cluster.x-k8s.io/ns: "testlabel" 101 name: "test" 102 --- 103 apiVersion: v1 104 kind: Secret 105 metadata: 106 name: "test-account-creds" 107 namespace: capa-system 108 stringData: 109 AccessKeyID: AKIAIOSFODNN7EXAMPLE 110 SecretAccessKey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY 111 ``` 112 113 ## AWSClusterRoleIdentity 114 `AWSClusterRoleIdentity` allows CAPA to assume a role either in the same or another AWS account, using the STS::AssumeRole API. 115 The assumed role could be used by the AWSClusters that is in the `allowedNamespaces`. 116 117 Example: 118 Below, an `AWSClusterRoleIdentity` instance, which will be used by `AWSCluster` "test", is created. 119 This role will be assumed by the source identity at runtime. Source identity can be of any identity type. 120 Role is assumed in the beginning once and after, whenever the assumed role's credentials are expired. 121 122 This snippet illustrates the connection between `AWSCluster`and the `AWSClusterRoleIdentity`, however this is not a working example. 123 Please view a full example below. 124 125 ```yaml 126 --- 127 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 128 kind: AWSCluster 129 metadata: 130 name: "test" 131 namespace: "test" 132 spec: 133 region: "eu-west-1" 134 identityRef: 135 kind: AWSClusterRoleIdentity 136 name: test-account-role 137 --- 138 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 139 kind: AWSClusterRoleIdentity 140 metadata: 141 name: "test-account-role" 142 spec: 143 allowedNamespaces: 144 - "test" # allows only "test" namespace to use this identity 145 roleARN: "arn:aws:iam::123456789:role/CAPARole" 146 sourceIdentityRef: 147 kind: AWSClusterControllerIdentity # use the singleton for root auth 148 name: default 149 ``` 150 151 Nested role assumption is also supported. 152 Example: Below, "multi-tenancy-nested-role" will be assumed by "multi-tenancy-role", which will be assumed by the "default" `AWSClusterControllerIdentity` 153 154 ```yaml 155 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 156 kind: AWSClusterRoleIdentity 157 metadata: 158 name: multi-tenancy-role 159 spec: 160 allowedNamespaces: 161 list: [] 162 durationSeconds: 900 # default and min value is 900 seconds 163 roleARN: arn:aws:iam::11122233344:role/multi-tenancy-role 164 sessionName: multi-tenancy-role-session 165 sourceidentityRef: 166 kind: AWSClusterControllerIdentity 167 name: default 168 --- 169 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 170 kind: AWSClusterRoleIdentity 171 metadata: 172 name: multi-tenancy-nested-role 173 spec: 174 allowedNamespaces: 175 list: [] 176 roleARN: arn:aws:iam::11122233355:role/multi-tenancy-nested-role 177 sessionName: multi-tenancy-nested-role-session 178 sourceidentityRef: 179 kind: AWSClusterRoleIdentity 180 name: multi-tenancy-role 181 ``` 182 183 184 ### Necessary permissions for assuming a role: 185 186 There are multiple AWS assume role permissions that need to be configured in order for the assume role to work: 187 - The source identity (user/role specified in the source identity field) should have IAM policy permissions that enable it to perform sts:AssumeRole operation. 188 ```json 189 { 190 "Version": "2012-10-17", 191 "Statement": [ 192 { 193 "Effect": "Allow", 194 "Action": "sts:AssumeRole", 195 "Resource": "*" 196 } 197 ] 198 } 199 ``` 200 201 - The target role (can be in a different AWS account) must be configured to allow the source user/role (or all users in an AWS account) to assume into it by setting a trust policy: 202 ``` json 203 { 204 "Version": "2012-10-17", 205 "Statement": [ 206 { 207 "Effect": "Allow", 208 "Principal": { 209 "AWS": "arn:aws:iam::111111111111:root" 210 // "AWS": "arn:aws:iam::111111111111:role/role-used-during-cluster-bootstrap" 211 }, 212 "Action": "sts:AssumeRole" 213 } 214 ] 215 } 216 ``` 217 218 ### Examples 219 220 This is a deployable example which uses the `AWSClusterRoleIdentity` "test-account-role" to assume into the `arn:aws:iam::123456789:role/CAPARole` role in the target account. 221 This example assumes that the `CAPARole` has already been configured in the target account. 222 223 Finally, we inform the `Cluster` to use our `AWSCluster`type to provision a cluster in the target account specified by the `identityRef` section. 224 225 **Note** 226 227 By default the `AutoControllerIdentityCreator=true` feature gate is set to `true` [here](https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/412d310654c6b05f1b4bc3d319f6957a07c009c2/feature/feature.go?rgh-link-date=2022-03-23T14%3A57%3A46Z#L81). 228 If this is not enabled for your cluster, you will need to enable the flag, or create your own default `AWSClusterControllerIdentity`. 229 230 ```yaml 231 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 232 kind: AWSClusterControllerIdentity 233 metadata: 234 name: "default" 235 spec: 236 allowedNamespaces:{} # matches all namespaces 237 ``` 238 239 ```yaml 240 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 241 kind: AWSClusterRoleIdentity 242 metadata: 243 name: "test-account-role" 244 spec: 245 allowedNamespaces: {} # matches all namespaces 246 roleARN: "arn:aws:iam::123456789:role/CAPARole" 247 sourceIdentityRef: 248 kind: AWSClusterControllerIdentity # use the singleton for root auth 249 name: default 250 --- 251 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 252 kind: AWSCluster 253 metadata: 254 name: "test-multi-tenant-workload" 255 spec: 256 region: "eu-west-1" 257 identityRef: 258 kind: AWSClusterRoleIdentity 259 name: test-account-role 260 --- 261 apiVersion: cluster.x-k8s.io/v1beta1 262 kind: Cluster 263 metadata: 264 name: "test-multi-tenant-workload" 265 spec: 266 infrastructureRef: 267 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 268 kind: AWSCluster 269 name: "test-multi-tenant-workload" 270 ``` 271 272 More specific examples can be referenced from the existing [templates](../../../../templates/) directory. 273 274 In order to use the [EC2 template](../../../../templates/cluster-template.yaml) with identity type, you can add the `identityRef` section to `kind: AWSCluster` spec section in the template. If you do not, CAPA will automatically add the default identity provider (which is usually your local account credentials). 275 276 Similarly, to use the [EKS template](../../../../templates/cluster-template-eks.yaml) with identity type, you can add the `identityRef` section to `kind: AWSManagedControlPlane` spec section in the template. If you do not, CAPA will automatically add the default identity provider (which is usually your local account credentials). 277 278 ## Secure Access to Identities 279 `allowedNamespaces` field is used to grant access to the namespaces to use Identities. 280 Only AWSClusters that are created in one of the Identity's allowed namespaces can use that Identity. 281 `allowedNamespaces` are defined by providing either a list of namespaces or label selector to select namespaces. 282 283 ### Examples 284 285 An empty `allowedNamespaces` indicates that the Identity can be used by all namespaces. 286 287 ```yaml 288 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 289 kind: AWSClusterControllerIdentity 290 spec: 291 allowedNamespaces:{} # matches all namespaces 292 ``` 293 294 Having a nil `list` and a nil `selector` is the same with having an empty `allowedNamespaces` (Identity can be used by all namespaces). 295 296 ```yaml 297 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 298 kind: AWSClusterControllerIdentity 299 spec: 300 allowedNamespaces: 301 list: nil 302 selector: nil 303 ``` 304 305 A nil `allowedNamespaces` indicates that the Identity cannot be used from any namespace. 306 307 ```yaml 308 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 309 kind: AWSClusterControllerIdentity 310 spec: 311 allowedNamespaces: # this is same with not providing the field at all or allowedNamespaces: null 312 ``` 313 314 The union of namespaces that are matched by `selector` and the namespaces that are in the `list` is granted access to the identity. 315 The namespaces that are not in the list and not matching the selector will not have access. 316 317 Nil or empty `list` matches no namespaces. Nil or empty `selector` matches no namespaces. 318 If `list` is nil and `selector` is empty OR `list` is empty and `selector` is nil, Identity cannot be used from any namespace. 319 Because in this case, `allowedNamespaces` is not empty or nil, and neither `list` nor `selector` allows any namespaces, so the union is empty. 320 321 ```yaml 322 # Matches no namespaces 323 allowedNamespaces: 324 list: [] 325 ``` 326 ```yaml 327 # Matches no namespaces 328 allowedNamespaces: 329 selector: {} 330 ``` 331 ```yaml 332 # Matches no namespaces 333 allowedNamespaces: 334 list: null 335 selector: {} 336 ``` 337 ```yaml 338 # Matches no namespaces 339 allowedNamespaces: 340 list: [] 341 selector: {} 342 ``` 343 344 **Important** The default behaviour of an empty label selector is to match all objects, however here we do not follow that behavior to avoid unintended access to the identities. 345 This is consistent with core cluster API selectors, e.g., Machine and ClusterResourceSet selectors. The result of matchLabels and matchExpressions are ANDed. 346 347 348 In Kubernetes selectors, `matchLabels` and `matchExpressions` are ANDed. 349 In the example below, list is empty/nil, so does not allow any namespaces and selector matches with only `default` namespace. 350 Since `list` and `selector` results are ORed, `default` namespace can use this identity. 351 352 ```yaml 353 kind: namespace 354 metadata: 355 name: default 356 labels: 357 environment: dev 358 --- 359 apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 360 kind: AWSClusterControllerIdentity 361 spec: 362 allowedNamespaces: 363 list: null # or [] 364 selector: 365 matchLabels: 366 namespace: default 367 matchExpressions: 368 - {key: environment, operator: In, values: [dev]} 369 ```