-
Notifications
You must be signed in to change notification settings - Fork 5
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
creds endpoint #4
Conversation
Generates k8s service accounts for the three operation modes: existing service account, existing role, and creating all objects from given role rules.
Tests Role and ClusterRole types, RoleBinding and ClusterRoleBinding creds options. Also uses more common testing functions.
For kubernetes_role_name, set the RoleBinding/ClusterRoleBinding as the owner of the ServiceAccount. For generated_role_rules, set the Role/ClusterRole as the owning object. Only the owner objects will have WAL entries written.
Check the annotations, labels, and rules/role references for created k8s objects in the integration tests. Adds a new service account (super-jwt) that has extra abilities to `get` the k8s objects.
return logical.ErrorResponse's when validation checks fail.
Can be skipped by setting SKIP_WAL_TEST in env.
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.
Looking good - I've still got the integration tests and path_creds.go to look at, sorry for the partial review.
Apply standard labels after user labels, so users can't override them. Set ForwardPerformanceSecondary and ForwardPerformanceStandby for the creds calls. Cap the lease and token ttl at creds time to the token_max_ttl and/or the system/mount max ttl.
More comments and logging. Directly assign the CACert instead of append'ing.
"created_role_type": role.K8sRoleType, | ||
}) | ||
|
||
resp.Secret.TTL = theTTL |
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.
It's possible the the k8s API may give us back a token with a TTL different from what we requested: https://kubernetes.io/docs/reference/kubernetes-api/authentication-resources/token-request-v1/#TokenRequestSpec
e.g. IIRC the minimum token TTL is 10 minutes. And there is also a kube-apiserver
flag --service-account-max-token-expiration
.
I haven't thought through how we should handle that too much, but we should at least add a warning to the response if there's a disparity.
If the returned TTL is longer, we can still effectively revoke early if there is a service account or role binding to delete, but we're a bit stuck if we're only generating a token.
If the returned TTL is shorter, we should probably pin the Vault lease down to the shorter TTL as well?
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.
Yep, good points. I added the warnings and set the Vault lease if the token TTL is shorter in c3e9ee6.
When requesting a token, apparently we could also tie it to a k8s object via the boundObjectRef
. So in the future perhaps we could create a simple Secret or something that is bound to the token, and would allow us to "revoke" the token in the existing service account case.
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 love that idea, I just tested it out and it works perfectly:
kubectl create secret generic foo
kubectl create token default --bound-object-kind Secret --bound-object-name foo
# The `foo` secret is still empty - no data attached.
kubectl proxy &
curl --silent http://127.0.0.1:8001/apis/authentication.k8s.io/v1/tokenreviews -H "Content-Type: application/json" -X POST -d '{"apiVersion": "authentication.k8s.io/v1", "kind": "TokenReview", "spec": {"token":"<JWT>"}}' | jq
# Authenticated
kubectl delete secret foo
# Repeating the TokenReview request now returns an error
Not in this PR, but we should definitely implement that.
if !ok { | ||
return logical.ErrorResponse("'kubernetes_namespace' is required"), nil | ||
} |
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.
Would it maybe make sense to allow omitting kubernetes_namespace
if there is only one namespace specified? It could simplify the UX in that case, but maybe it also has potential to make things more confusing. In any case, this definitely doesn't need addressing in this PR, as it's easy to relax the rule later.
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.
Yeah! I think that would be sensible default behavior.
Co-authored-by: Tom Proctor <[email protected]>
Do some template validation on role create/update. Test a custom name template in one of the integration tests. Write the WAL entry before the k8s object is created. Add more doc strings about the WAL + owner reference scheme. Add missing WAL giving up log message for rollbackRoleWAL.
…secrets-kubernetes into VAULT-5671/creds
Use a single mutex lock for getClient(). Check the k8s token ttl and return a warning if it's larger than the lease ttl, also warn and set the lease TTL = token TTL if the token's is shorter. Also test the RoleBinding WAL path in wal_rollback_test.go.
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.
👍 Other than the open suggestions from others, and a follow up to Christopher's comment I didn't find much else to add.
since vault is building with go 1.17
// Eventually expire the WAL if for some reason the rollback operation consistently fails | ||
var maxWALAge = 24 * time.Hour | ||
|
||
func (b *backend) walRollback(ctx context.Context, req *logical.Request, kind string, data interface{}) error { |
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.
AFAICT I think it's currently possible for createCreds
and walRollback
to run simultaneously, which could result in walRollback
revoking some credentials that are part way through being provisioned.
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.
That is mitigated somewhat by the WALRollbackMinAge, which defaults to 10 minutes: https://github.com/hashicorp/vault/blob/ab0944d9653f41df7c8091adbbf3b8e516a2f58e/sdk/framework/backend.go#L577-L582
i.e. credentials/objects in K8s need to have been created for at least 10 minutes before they'll start being processed in walRollback. This is also why the integration test takes ~10 minutes to run since there's a rollback test.
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.
Ahh cool, I missed that. Sounds fine then. Although on another note, maybe it would be good to try and bring that integration test time down in a future PR.
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.
Ohh, I didn't realize that reverting to the default value also delays the test by that amount. Is there a way to just reduce the min age for the test?
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.
Yeah we'll have to look into changing that for the integration tests. Perhaps with some compile flags or something.
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.
🎉 No blockers from me
Overview
Implementation of the
creds
endpoint for generating the credentials for the service account.Design of Change
The
creds
endpoint has these parameters:name (string: <required>)
: The name of the role.kubernetes_namespace (string: <required>)
: The name of the Kubernetes namespace in which to generate the service account.cluster_role_binding (bool: false)
: If true, generate a ClusterRoleBinding to grant permissions across the whole cluster instead of within a namespace. Requires the Vault role to have kubernetes_role_type set to ClusterRole.ttl (string: "")
: The ttl of the generated Kubernetes service account.Other notes:
make setup-integration-test integration-test TESTARGS="-v" SKIP_WAL_TEST=yes
When the creds create fails in the wal tests, something retries the path_creds request a couple time, so three sets of orphaned objects are created. They all are cleaned up properly by the WAL, but I'm not sure what's retrying the path_creds call.Nevermind, this is probably just the built-in retries in the vault client we're using in the tests.Testing examples
The integration tests can be run as described in the README.
Manual testing:
You can also configure this with Vault running outside kubernetes, something like this: