crossplane-contrib / provider-upjet-aws

AWS Provider for Crossplane.
https://marketplace.upbound.io/providers/upbound/provider-family-aws/
Apache License 2.0
146 stars 122 forks source link

How to use least-privilege with AWS accounts #954

Closed RobCannon closed 2 months ago

RobCannon commented 11 months ago

What problem are you facing?

I am trying to make sure that we are using the principles of least privilege when using AWS roles in Crossplane.

How could Official AWS Provider help solve your problem?

I don't think it is really possible.

Providers are all Cluster scopes and all Crossplane AWS resources are cluster scoped. We want to allow developers to create resources in a constrained manner. So maybe developers can create S3 resources, but not IAM or SecretManager resources. Maybe they should be able to read only specific secrets.

So, I create a provider that has higher privileges and can create the secrets and IAM roles:

apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
  name: provider-aws-low-privilege
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::{{ .Values.accountId }}:role/k8s-xp-low-privledge
spec:
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-s3
spec:
  package: xpkg.upbound.io/upbound/provider-aws-s3:latest
  controllerConfigRef:
    name: provider-aws-low-privilege
---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: provider-aws-low-privilege
spec:
  credentials:
    source: IRSA

I am not even sure what links the ProviderConfig to a specific role at this point. Is there anything or is there only one role used by the provider?

Assuming that I can create two ProviderConfigs that are bound to different AWS roles:

apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-secretsmanager
spec:
  package: xpkg.upbound.io/upbound/provider-aws-secretsmanager:latest
  controllerConfigRef:
    name: provider-aws-high-privilege
---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: provider-aws-high-privilege
spec:
  credentials:
    source: IRSA

What would keep a developer from just using a high-privilege account? If everything is Cluster level, how do I control access to a particular ProviderConfig? Limiting an AWS role to a namespace is how we do this with something like Pulumi.

apiVersion: secretsmanager.aws.upbound.io/v1beta1
kind: Secret
metadata:
  name: test-secret
spec:
  forProvider:
    region: us-east-2
  providerConfigRef:
    name: provider-aws-high-privilege

Also, it really looks like I need to configure a Provider for each permutation of AWS resource type and AWS role? It seems like the design here is really around all providers have god-mode access to their resources.

Am I missing something?

bobh66 commented 11 months ago

You can only create/deploy one Provider instance for each type, but you can have it running with low permissions and use IRSA to assume role(s) that have the privileges it needs to do the things you want.

So if you have a set of developers who are allowed to create EKS clusters, create a Role in AWS with the privileges to do that, and allow that role to be assumed by the role that IRSA is using for the Provider.

Create a ProviderConfig that specifies the EKS Cluster create role to be assumed and have the developers use that ProviderConfig

You can create AWS Roles/ProviderConfigs for whatever sets of permissions you want to create,

You would need some way to enforce what ProviderConfig is used for each team but there are a number of solutions for that.

Does that make sense?

RobCannon commented 11 months ago

You would need some way to enforce what ProviderConfig is used for each team but there are a number of solutions for that.

OK, maybe that is what I am missing. We are using ArgoCD, so when a resource is created, if I can't restrict it to a service account that is bound to that namespace, how do I prevent a team from picking any ProviderConfig? They only thing I can think of is something to validate the code at check-in but that seems easy to bypass.

bobh66 commented 11 months ago

Are you using ArgoCD to create MRs directly with no Compositions?

Can you use kustomize with ArgoCD to enforce a specific providerConfigRef.name for each MR that gets created?

If you use Compositions you could patch the claim-namespace as a key for the providerConfigRef.name (for example), assuming that you can restrict the claim creation to specific namespaces for specific teams

RobCannon commented 11 months ago

Well, it is wide open on what we use. I am trying to determine if we can use this instead of Pulumi and how we would organize this for a cluster that runs 75 or so applications (namespace) built by a dozen teams.

I still don't see how a ProviderConfig is linked to a specific role. Does the name of the ProviderConfig need to match the name of the Provider. Which would mean I have to create a Provider for each resource/role permutation?

It would be easier if the ServiceAccount name was specified in the ProviderConfig. I guess the ServiceAccount has to be created in the crossplane-system namespace?

bobh66 commented 11 months ago

The ProviderConfig specifies the Role to be assumed to create the specific MR/ See https://github.com/upbound/provider-aws/blob/main/AUTHENTICATION.md#web-identity for more details.

There are a number of ways to organize this - you could have a Role / ProviderConfig for each namespace/application which would allow only the specific permissions needed for that application, and use the namespace name for the ProviderConfig name so the composition just uses claim-namespace for the providerConfigRef.name

What do you mean by "Service" in this context?

RobCannon commented 11 months ago

Sorry, I meant ServiceAccount. I edited the comment.

github-actions[bot] commented 6 months ago

This provider repo does not have enough maintainers to address every issue. Since there has been no activity in the last 90 days it is now marked as stale. It will be closed in 14 days if no further activity occurs. Leaving a comment starting with /fresh will mark this issue as not stale.

github-actions[bot] commented 2 months ago

This provider repo does not have enough maintainers to address every issue. Since there has been no activity in the last 90 days it is now marked as stale. It will be closed in 14 days if no further activity occurs. Leaving a comment starting with /fresh will mark this issue as not stale.

github-actions[bot] commented 2 months ago

This issue is being closed since there has been no activity for 14 days since marking it as stale. If you still need help, feel free to comment or reopen the issue!