-
Notifications
You must be signed in to change notification settings - Fork 900
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use serviceAccountName for Service Account creation #2880
Conversation
Updates the name of a Service Account, which is to be created by a controller, to be specified by the `.spec.serviceAccountName` field of `ControllerConfig` if specified. It's currently named the same name of a `ProviderRevision` even if the `.spec.serviceAccountName` is specified whereas the `.spec.template.spec.serviceAccountName` in a Deployment is specified by it. This approach wouldn't make a lot of sense because: - ClusterRolebindings to be created by a controller target only Service Accounts that are managed by the controller so necessary Roles aren't granted to a Service Account defined in a `ControllerConfig` by default. - Inconstant names aren't helpful in some cases. A notable example is Workload Identity in GCP, where a Kubernetes Service Account needs to specified in IAM binding. With the current implementation, whenever a new `ProvierRevision` is created, which means a Service Account is "renamed", IAM binding for Workload Identity also needs to be updated. Though Workload Identity isn't supported in `provider-gcp`, this would meet one of the requirements to support it. On the other hand, there wouldn't be a lot of practical use cases where it's necessary to specify a custom Service Account to a Deployment and keep letting a controller create Service Accounts with different names. Signed-off-by: micnncim <micnncim@gmail.com>
@@ -116,6 +116,9 @@ func buildProviderDeployment(provider *pkgmetav1.Provider, revision v1.PackageRe | |||
s.Annotations = cc.Annotations | |||
d.Labels = cc.Labels | |||
d.Annotations = cc.Annotations | |||
if cc.Spec.ServiceAccountName != nil { | |||
s.Name = *cc.Spec.ServiceAccountName |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that this would simplify most cases where people pass a ServiceAccountName
today.
I am a bit hesitant due to the following:
- This could be a breaking change for existing setups where a
ServiceAccount
is created separately. - I don't feel much comfortable API-wise. So far, any configurations there (except labels/annotations, i.e. metadata) were only affecting the pod spec.
@hasheddan what do you think? Any previous discussion on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can understand your concern. I have another idea as below to realize my intention without breaking the compatibility or affecting other resources than Pods:
- Add a new label, for example
crossplane.io/service-account
, to be used in a user-managed ServiceAccount, optionally - Update the logic to reconcile ClusterRoleBindings to create a ClusterRoleBinding for a user-managed ServiceAccount alongside with controller-managed ServiceAccounts if it has the above label
In this approach, in addition to resolving your concern, users can choose to both keep the current behavior and have their ServiceAccount be granted a necessary ClusterRole.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This PR should not have been closed and implements exactly the behaviour I would have expected. Furthermore it is a required building block for being able to implement Crossplane deployments that utilise workload identity (e.g. EKS IRSA) grounded in K8s service accounts. Please consider merging this! |
@turkenh Hi, any discussion about this you've had in the team or community? I still believe some people want some kind of this update. |
@micnncim sorry for the delay here.
I believe M1 Mac is supported now, could you do some local testing and update the PR description accordingly. I would really appreciate if you could also test how it behaves on a setup where user has manually created that service account beforehand, would it fail or simply adapt it without any error to make sure whether this would be a breaking change or not? |
Thank you for the ping, @turkenh!
I've rebased this PR against the current
and created a local kind test cluster by following the instructions for establishing a development environment. The deployed versions were:
New ServiceAccountI've created the following ---
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: crossplane-provider-aws-config
annotations:
eks.amazonaws.com/role-arn: aws:iam::01234567890:role/crossplane-provider-aws
some.other.annotation: foobar
spec:
args:
- --enable-external-secret-stores
serviceAccountName: crossplane-provider-aws
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: crossplane-provider-aws
spec:
package: crossplanecontrib/provider-aws:v0.34.0
controllerConfigRef:
name: crossplane-provider-aws-config Once applied, a new ❯ k get provider
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-provider-aws True True crossplanecontrib/provider-aws:v0.34.0 45s
❯ k get serviceaccounts -n crossplane-system
NAME SECRETS AGE
crossplane 0 10m
crossplane-provider-aws 0 6s
default 0 10m
rbac-manager 0 10m with the expected ❯ k describe clusterrolebindings.rbac.authorization.k8s.io crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Name: crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount crossplane-provider-aws crossplane-system
❯ k describe serviceaccounts -n crossplane-system crossplane-provider-aws
Name: crossplane-provider-aws
Namespace: crossplane-system
Labels: <none>
Annotations: eks.amazonaws.com/role-arn: aws:iam::01234567890:role/crossplane-provider-aws
some.other.annotation: foobar
... Existing ServiceAccountThe behaviour is as desired when the specified ❯ k get serviceaccounts -n crossplane-system
NAME SECRETS AGE
crossplane 0 139m
default 0 139m
rbac-manager 0 139m
❯ k create serviceaccount -n crossplane-system crossplane-provider-aws
serviceaccount/crossplane-provider-aws created
❯ k describe serviceaccounts -n crossplane-system crossplane-provider-aws
Name: crossplane-provider-aws
Namespace: crossplane-system
Labels: <none>
Annotations: <none>
... Specifically, the corresponding ❯ k get clusterrolebindings.rbac.authorization.k8s.io|grep cross
crossplane ClusterRole/crossplane 139m
crossplane-admin ClusterRole/crossplane-admin 139m
crossplane-rbac-manager ClusterRole/crossplane-rbac-manager 139m
❯ k describe clusterrolebindings.rbac.authorization.k8s.io crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Error from server (NotFound): clusterrolebindings.rbac.authorization.k8s.io "crossplane:provider:crossplane-provider-aws-6707d06fe75f:system" not found Lets apply ❯ k apply -f configure/aws/provider.yaml
controllerconfig.pkg.crossplane.io/crossplane-provider-aws-config created
provider.pkg.crossplane.io/crossplane-provider-aws created
❯ k get provider
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-provider-aws True Unknown crossplanecontrib/provider-aws:v0.34.0 5s We can see that the ❯ k describe clusterrolebindings.rbac.authorization.k8s.io crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Name: crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Subjects:
Kind Name Namespace
---- ---- --------- Which changes in a couple of reconciliation loops and when the provider becomes healthy: ❯ k get provider
NAME INSTALLED HEALTHY PACKAGE AGE
crossplane-provider-aws True True crossplanecontrib/provider-aws:v0.34.0 60s
❯ k describe clusterrolebindings.rbac.authorization.k8s.io crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Name: crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: crossplane:provider:crossplane-provider-aws-6707d06fe75f:system
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount crossplane-provider-aws crossplane-system and the ❯ k describe serviceaccounts -n crossplane-system crossplane-provider-aws
Name: crossplane-provider-aws
Namespace: crossplane-system
Labels: <none>
Annotations: eks.amazonaws.com/role-arn: aws:iam::01234567890:role/crossplane-provider-aws
some.other.annotation: foobar
... If the existing ❯ k annotate serviceaccounts -n crossplane-system crossplane-provider-aws some.existing.annotation=quux
serviceaccount/crossplane-provider-aws annotated
❯ k describe serviceaccounts -n crossplane-system crossplane-provider-aws
Name: crossplane-provider-aws
Namespace: crossplane-system
Labels: <none>
Annotations: some.existing.annotation: quux
...
❯ k apply -f configure/aws/provider.yaml
controllerconfig.pkg.crossplane.io/crossplane-provider-aws-config created
provider.pkg.crossplane.io/crossplane-provider-aws created
❯ k describe serviceaccounts -n crossplane-system crossplane-provider-aws
Name: crossplane-provider-aws
Namespace: crossplane-system
Labels: <none>
Annotations: eks.amazonaws.com/role-arn: aws:iam::01234567890:role/crossplane-provider-aws
some.existing.annotation: quux
some.other.annotation: foobar
... It should be noted that the ❯ k get serviceaccounts -n crossplane-system
NAME SECRETS AGE
crossplane 0 12m
crossplane-provider-aws 0 7m33s
default 0 12m
rbac-manager 0 12m
❯ k delete -f configure/aws/provider.yaml
controllerconfig.pkg.crossplane.io "crossplane-provider-aws-config" deleted
provider.pkg.crossplane.io "crossplane-provider-aws" deleted
❯ k get serviceaccounts -n crossplane-system
NAME SECRETS AGE
crossplane 0 12m
default 0 12m
rbac-manager 0 12m ConclusionIn summary, we are seeing the desired behaviour:
The only slightly problematic aspect is that service accounts are deleted, regardless if they they were created by Crossplane or were in place already. |
This would be great, it is a real issue otherwise to deploy when using Infra-as-code like Terraform when you cannot control the resources created as part of the provider like |
Another +1 for this effort. A lot of folks are moving towards managed identities that are tied to K8s service accounts in the provider's IAM system (IRSA, GCP Workload Identity, etc.) |
@wwentland Thanks a lot for the detailed testing! @turkenh Can you take another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wwentland, thanks a lot for the detailed testing 🙌 All looks good to me!
and thanks, @micnncim, for proposing this change in the first place 🙌
Description of your changes
Updates the name of a Service Account, which is to be created by a controller, to be specified by the
.spec.serviceAccountName
field ofControllerConfig
if specified.It's currently named the same name of a
ProviderRevision
even if the.spec.serviceAccountName
is specified whereas the.spec.template.spec.serviceAccountName
in a Deployment is specified by it.The current approach wouldn't make a lot of sense because:
ControllerConfig
by default.ProvierRevision
is created, which means a Service Account is "renamed", IAM binding for Workload Identity also needs to be updated. Though Workload Identity isn't supported inprovider-gcp
yet, this would meet one of the requirements to support it.On the other hand, there wouldn't be a lot of practical use cases where it's necessary to specify a custom Service Account to a Deployment and keep letting a controller create Service Accounts with different names.
Signed-off-by: micnncim micnncim@gmail.com
Fixes #2295
I have:
make reviewable
to ensure this PR is ready for review.backport release-x.y
labels to auto-backport this PR if necessary.How has this code been tested
See #2880 (comment)