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  ```