-
Notifications
You must be signed in to change notification settings - Fork 39.8k
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
migrate group approver to use subject access reviews #45619
Conversation
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: mikedanese
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
@@ -185,7 +185,7 @@ func (s *CMServer) AddFlags(fs *pflag.FlagSet, allControllers []string, disabled | |||
fs.StringVar(&s.ServiceAccountKeyFile, "service-account-private-key-file", s.ServiceAccountKeyFile, "Filename containing a PEM-encoded private RSA or ECDSA key used to sign service account tokens.") | |||
fs.StringVar(&s.ClusterSigningCertFile, "cluster-signing-cert-file", s.ClusterSigningCertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates") | |||
fs.StringVar(&s.ClusterSigningKeyFile, "cluster-signing-key-file", s.ClusterSigningKeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates") | |||
fs.StringVar(&s.ApproveAllKubeletCSRsForGroup, "insecure-experimental-approve-all-kubelet-csrs-for-group", s.ApproveAllKubeletCSRsForGroup, "The group for which the controller-manager will auto approve all CSRs for kubelet client certificates.") | |||
fs.BoolVar(&s.EnableKubeletCSRApprover, "enable-kubelet-csr-approver", s.EnableKubeletCSRApprover, "Enable the kubelet CSR approver which approves kubelet CSRs based on subject access reviews") |
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.
Do we need an option for this or can we just leave it on?
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.
When the auto-approving controller is its own controller, you would use --controllers=...
to decide whether to run it or not. I wouldn't enable it by default yet. For example, if it was named autoapprove-kubelet-csrs
and was not on by default, you would specify --controllers=*,autoapprove-kubelet-csrs
to run all on-by-default controllers and the autoapprover.
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.
oh, I see this already splits it out
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.
Ok, I'll drop it.
@@ -311,7 +311,8 @@ func NewControllerInitializers() map[string]InitFunc { | |||
controllers["disruption"] = startDisruptionController | |||
controllers["statefuleset"] = startStatefulSetController | |||
controllers["cronjob"] = startCronJobController | |||
controllers["certificatesigningrequests"] = startCSRController | |||
controllers["certificatesigningrequestssigning"] = startCSRSigningController | |||
controllers["certificatesigningrequestsapproving"] = startCSRApprovingController |
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.
Changing the controller name needs a release note since people can address it via --controllers
. If we're changing it, shorter might be better? Something like csrsigner
/ csrautoapprover
?
pkg/apis/componentconfig/types.go
Outdated
ApproveAllKubeletCSRsForGroup string | ||
// enableKubeletCSRApprover tells the CSR controller to approve | ||
// kubelet CSRs based on SubjectAccessReviews. | ||
EnableKubeletCSRApprover bool |
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.
not needed, use controller name in Controllers
utilruntime.HandleError(fmt.Errorf("unable to parse csr %q: %v", csr.Name, err)) | ||
return csr, nil | ||
} | ||
if !reflect.DeepEqual([]string{"system:nodes"}, x509cr.Subject.Organization) { |
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 wouldn't expect this to be true for node serving certs
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 attempted to match the behavior here: https://github.com/kubernetes/kubernetes/pull/45059/files#diff-bf28da68f62a8df6e99e447c4351122dR1060
if !reflect.DeepEqual([]string{"system:nodes"}, x509cr.Subject.Organization) { | ||
return csr, nil | ||
} | ||
if len(x509cr.DNSNames)+len(x509cr.EmailAddresses)+len(x509cr.IPAddresses) != 0 { |
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.
this will not be true for node serving certs
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.
Same as above. I will adjust when #45059 settles.
if err != nil { | ||
utilruntime.HandleError(fmt.Errorf("unable to parse csr %q: %v", csr.Name, err)) | ||
return csr, 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.
I expected this to be structured more in terms of recognizers and associated permission required.
type CSRRecognizer interface {
Matches(csrObj, parsedCSR) bool
}
recognizers := []struct{
recognizer CSRRecognizer
permission authorizer.ResourceAttributes
}{
{
recognizer: isSelfNodeClientCert,
permission: authorizer.ResourceAttributes{Group: "certificates.k8s.io", Resource: "certificatesigningrequests", Subresource: "selfnodeclient"},
},
{
recognizer: isNodeClientCert,
permission: authorizer.ResourceAttributes{Group: "certificates.k8s.io", Resource: "certificatesigningrequests", Subresource: "nodeclient"},
},
{
recognizer: isSelfNodeClientCert,
permission: authorizer.ResourceAttributes{Group: "certificates.k8s.io", Resource: "certificatesigningrequests", Subresource: "selfnodeclient"},
},
{
recognizer: isNodeClientCert,
permission: authorizer.ResourceAttributes{Group: "certificates.k8s.io", Resource: "certificatesigningrequests", Subresource: "nodeclient"},
},
}
func autoApprove(csrObj) {
// short-circuit on pre-approved
parsedCSR, err := parse(csrObj)
// short-circuit on error
for _, r := range recognizers {
if !r.recognizer.Matches(csrObj, parsedCSR) {
continue
}
approved, err := authorize(csrObj, r.permission)
if err != nil {
// accumulate error in case we ultimately fail?
continue
}
if approved {
// record approval
}
}
}
return csr, nil | ||
} | ||
} | ||
if hasExactUsages(csr, kubeletServerUsages) { |
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.
have you thought about how we'd verify what hostnames and subjectaltnames a kubelet is allowed to ask for in its serving cert? In non-cloud-provider setups, the only info we have about the node is self-reported today in node status (which isn't even available until the kubelet self-registers, which is probably after the serving cert bootstrap). In cloud-provider cases, are we able to ask the cloud provider for the hostnames/dns names/IP addresses for an arbitrary node?
cc @kubernetes/sig-auth-pr-reviews closes #45030? |
@ericchiang yest this closes #45030 |
if !hasExactUsages(csr, kubeletServerUsages) { | ||
return false | ||
} | ||
//TODO(jcbsmpsn): implement the rest of 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.
@jcbsmpsn I expect you will want to fill this in once we know how kubelet certs are going to look.
b518a7e
to
d4f7b99
Compare
@liggitt Please rereview this (especially the second commit) |
The behavior was alpha and the flag was marked experimental. I'd consider marking the flag as deprecated and making it inert for a release |
} | ||
|
||
func isNodeClientCert(csr *capi.CertificateSigningRequest, x509cr *x509.CertificateRequest) bool { | ||
if !reflect.DeepEqual([]string{"system:nodes"}, x509cr.Subject.Organization) { |
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.
Is there a canonical constant on this anywhere?
if !hasExactUsages(csr, kubeletClientUsages) { | ||
return false | ||
} | ||
if !strings.HasPrefix(x509cr.Subject.CommonName, "system:node:") { |
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.
...or 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.
This existed in the previous code.
if !hasExactUsages(csr, kubeletServerUsages) { | ||
return false | ||
} | ||
//TODO(jcbsmpsn): implement the rest of 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.
critical for v1.7?
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 it is not.
I'm fine with one release cycle as the deprecation period, so we'll remove this in v1.8 then... |
@@ -192,7 +192,6 @@ func (s *CMServer) AddFlags(fs *pflag.FlagSet, allControllers []string, disabled | |||
fs.StringVar(&s.ServiceAccountKeyFile, "service-account-private-key-file", s.ServiceAccountKeyFile, "Filename containing a PEM-encoded private RSA or ECDSA key used to sign service account tokens.") | |||
fs.StringVar(&s.ClusterSigningCertFile, "cluster-signing-cert-file", s.ClusterSigningCertFile, "Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates") | |||
fs.StringVar(&s.ClusterSigningKeyFile, "cluster-signing-key-file", s.ClusterSigningKeyFile, "Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates") | |||
fs.StringVar(&s.ApproveAllKubeletCSRsForGroup, "insecure-experimental-approve-all-kubelet-csrs-for-group", s.ApproveAllKubeletCSRsForGroup, "The group for which the controller-manager will auto approve all CSRs for kubelet client certificates.") |
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.
@mikedanese please re-add the flag, make it inert (it doesn't need to bind to anything), mark it as deprecated and describe the replacement mechanism. We'll remove it completely in 1.8.
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.
Done.
This is not neccessary to get in on the first pass. |
nit on short-circuiting CSRs that already have a cert issued in status, LGTM otherwise as a first-pass |
Ok, will addresss and add lgtm label. |
There is a bit of good feedback that isn't necessary for 1.7 and that I won't be able to get to before code freeze. I opened #46638 to get back to it. |
@k8s-bot pull-kubernetes-unit test this |
Automatic merge from submit-queue (batch tested with PRs 46635, 45619, 46637, 45059, 46415) |
thanks, can you open doc PRs against the TLS bootstrapping topic and the authorization topic (to call out the subresources used to authorize) |
Automatic merge from submit-queue (batch tested with PRs 46897, 46899, 46864, 46854, 46875) kubeadm: Make kubeadm use the right CSR approver for the right version **What this PR does / why we need it**: fixes regression caused in: kubernetes#45619 **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # Fixes: kubernetes/kubeadm#289 **Special notes for your reviewer**: cc @pipejakob our e2e CI should probably go green after this change **Release note**: ```release-note NONE ``` @mikedanese @pipejakob @timothysc @liggitt
WIP, needs test and changes to kubeadm
depends on #45514