Skip to content

Commit

Permalink
feat: add flag to disable CSR denial
Browse files Browse the repository at this point in the history
in that mode, CSR which are not automatically approved are simply left
untouched.

closes #293

Signed-off-by: Clément Nussbaumer <[email protected]>
  • Loading branch information
clementnuss committed Dec 30, 2024
1 parent 44e2c43 commit e138f46
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 13 deletions.
4 changes: 3 additions & 1 deletion internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ func prepareCmdlineConfig() *controller.Config {
bypassDNSResolution = fs.Bool("bypass-dns-resolution", false, "set this parameter to true to bypass DNS resolution checks")
bypassHostnameCheck = fs.Bool("bypass-hostname-check", false, "set this parameter to true to ignore mismatching DNS name and hostname")
ignoreNonSystemNodeCsr = fs.Bool("ignore-non-system-node", false, "set this parameter to true to ignore CSR for subjects different than system:node")
skipDenyCSR = fs.Bool("skip-deny-step", false, "set this parameter to skip denying non-compliant csr")
allowedDNSNames = fs.Int("allowed-dns-names", 1, "number of DNS SAN names allowed in a certificate request. defaults to 1")
ipPrefixesStr = fs.String("provider-ip-prefixes", "0.0.0.0/0,::/0",
`provider-specified, comma separated ip prefixes that CSR IP addresses shall fall into.
Expand All @@ -185,7 +186,7 @@ func prepareCmdlineConfig() *controller.Config {
}

config := controller.Config{
LogLevel: *logLevel,
LogLevel: int8(*logLevel),
MetricsAddr: *metricsAddr,
ProbeAddr: *probeAddr,
LeaderElection: *leaderElection,
Expand All @@ -194,6 +195,7 @@ func prepareCmdlineConfig() *controller.Config {
BypassDNSResolution: *bypassDNSResolution,
BypassHostnameCheck: *bypassHostnameCheck,
IgnoreNonSystemNodeCsr: *ignoreNonSystemNodeCsr,
SkipDenyCSR: *skipDenyCSR,
MaxExpirationSeconds: int32(*maxSec),
AllowedDNSNames: *allowedDNSNames,
}
Expand Down
29 changes: 17 additions & 12 deletions internal/controller/csr_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"fmt"
"strings"

"github.com/go-logr/logr"
"go4.org/netipx"
certificatesv1 "k8s.io/api/certificates/v1"
corev1 "k8s.io/api/core/v1"
Expand All @@ -47,7 +48,7 @@ type HostResolver interface {

// Config holds all variables needed to configure the controller
type Config struct {
LogLevel int
LogLevel int8
MetricsAddr string
ProbeAddr string
LeaderElection bool
Expand All @@ -60,6 +61,7 @@ type Config struct {
DNSResolver HostResolver
BypassDNSResolution bool
IgnoreNonSystemNodeCsr bool
SkipDenyCSR bool
AllowedDNSNames int
BypassHostnameCheck bool
}
Expand Down Expand Up @@ -128,18 +130,18 @@ func (r *CertificateSigningRequestReconciler) Reconcile(ctx context.Context, req
reason := "CSR Spec.Username is not prefixed with system:node:"
l.V(0).Info(logDenyingCSR + reason)

appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else if len(x509cr.DNSNames)+len(x509cr.IPAddresses) == 0 {
reason := "The x509 Cert Request SAN contains neither an IP address nor a DNS name"
l.V(0).Info(logDenyingCSR + reason)

appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else if x509cr.Subject.CommonName != csr.Spec.Username {
reason := "CSR username does not match the parsed x509 certificate request commonname"
l.V(0).Info(logDenyingCSR+reason,
"commonName", x509cr.Subject.CommonName, "specUsername", csr.Spec.Username)

appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else if valid, reason, err := r.DNSCheck(ctx, &csr, x509cr); !valid {
if err != nil {
l.V(0).Error(err, reason)
Expand All @@ -148,26 +150,26 @@ func (r *CertificateSigningRequestReconciler) Reconcile(ctx context.Context, req

l.V(0).Info("Denying kubelet-serving CSR. DNS checks failed. Reason:" + reason)

appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else if valid, reason, err := r.WhitelistedIPCheck(&csr, x509cr); !valid {
if err != nil {
l.V(0).Error(err, reason)
return res, err // returning a non-nil error to make this request be processed again in the reconcile function
}

l.V(0).Info("Denying kubelet-serving CSR. IP whitelist check failed. Reason:" + reason)
appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else if csr.Spec.ExpirationSeconds != nil && *csr.Spec.ExpirationSeconds > r.MaxExpirationSeconds {
reason := "CSR spec.expirationSeconds is longer than the maximum allowed expiration second"
l.V(0).Info("Denying kubelet-serving CSR. Reason:" + reason)

appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else if valid, reason := ProviderChecks(&csr, x509cr); !valid {
l.V(0).Info("CSR request did not pass the provider-specific tests. Reason: " + reason)
appendCondition(&csr, false, reason)
r.appendCondition(&csr, false, reason, l)
} else {
l.V(0).Info("CSR approved")
appendCondition(&csr, true, "")
r.appendCondition(&csr, true, "", l)
}

_, err = r.ClientSet.CertificatesV1().CertificateSigningRequests().UpdateApproval(ctx, req.Name, &csr, metav1.UpdateOptions{})
Expand All @@ -184,8 +186,9 @@ func (r *CertificateSigningRequestReconciler) Reconcile(ctx context.Context, req
return res, nil
}

func appendCondition(csr *certificatesv1.CertificateSigningRequest, approved bool, reason string) {
if approved {
func (r *CertificateSigningRequestReconciler) appendCondition(csr *certificatesv1.CertificateSigningRequest, approved bool, reason string, l logr.Logger) {
switch {
case approved:
csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateApproved,
Status: corev1.ConditionTrue,
Expand All @@ -194,7 +197,9 @@ func appendCondition(csr *certificatesv1.CertificateSigningRequest, approved boo
LastUpdateTime: metav1.Now(),
LastTransitionTime: metav1.Time{},
})
} else {
case r.SkipDenyCSR:
l.V(0).Info("Skipping the 'deny' step, the CSR will be left untouched.")
case !approved:
csr.Status.Conditions = append(csr.Status.Conditions, certificatesv1.CertificateSigningRequestCondition{
Type: certificatesv1.CertificateDenied,
Status: corev1.ConditionTrue,
Expand Down

0 comments on commit e138f46

Please sign in to comment.