kubelet-csr-approver

repository·main·Indexed 42 days ago

https://github.com/postfinance/kubelet-csr-approver

A Kubernetes controller that safely auto-approves 'kubelet-serving' Certificate Signing Requests (CSRs). It implements security verifications on hostnames, IP addresses, and identities—including regex validation and IP prefix checks—to prevent the forging of valid node certificates.

Tokens
2.4K
Snippets
5
Records
8
Agent score
53%

What's inside kubelet-csr-approver

  1. How kubelet-csr-approver validates CSRs

    main

    The controller implements several security verifications to prevent forged certificates. A CSR is approved only if it meets the following criteria:

    • Signer Name: CSR.Spec.SignerName must be kubernetes.io/kubelet-serving.
    • Expiration: CSR.Spec.ExpirationSeconds must be less than MAX_EXPIRATION_SEC.
    • Identity: CSR.Spec.Username must be prefixed with system:node:.
    • Common Name: The x509 CR CommonName must match the CSR.Spec.Username.
    • SAN Count: Subject Alternative Names (SAN) must contain at most one entry (controlled by --allowed-dns-names).
    • SAN Content: At least one SAN IP address or SAN DNS Name must be specified.
    • Hostname Match: If a SAN DNS Name is provided, it must comply with the --provider-regex and be prefixed by the node hostname (derived from CSR.Spec.Username).
    • IP Resolution: SAN IP addresses must be part of the set of IPs resolved from the SAN DNS Name.
    • Network Bounds: All SAN DNS Names and IP addresses must fall within the ranges specified by --provider-ip-prefixes.
  2. Install kubelet-csr-approver via Helm

    main

    You can install the kubelet-csr-approver controller into your Kubernetes cluster using Helm. It is recommended to install it in the kube-system namespace. You should customize the providerRegex, providerIpPrefixes, and maxExpirationSeconds parameters to match your environment's node naming conventions and network topology.

    helm repo add kubelet-csr-approver https://postfinance.github.io/kubelet-csr-approver
    helm install kubelet-csr-approver kubelet-csr-approver/kubelet-csr-approver -n kube-system \
      --set providerRegex='^node-\w*\.int\.company\.ch$'
      --set providerIpPrefixes='192.168.8.0/22'
      --set maxExpirationSeconds='86400'
      --set bypassDnsResolution='false'
  3. Quick start: Deploy and configure kubelet-csr-approver

    main

    To enable auto-approval of kubelet-serving Certificate Signing Requests (CSRs), follow these steps:

    1. Deploy the controller: Use the manifests located in deploy/k8s to deploy kubelet-csr-approver to your Kubernetes cluster.
    2. Configure Kubelet: Update your kubelet configuration file (typically at /var/lib/kubelet/config.yaml) to include the following field:
      serverTLSBootstrap: true
    3. Restart Kubelet: Restart the kubelet service to apply the changes.

    Once configured, the controller will automatically approve or deny CSRs based on your deployment parameters.

    yaml
    serverTLSBootstrap: true
  4. Configure kubelet-csr-approver parameters

    main

    The controller is configured via CLI flags or environment variables. These parameters control the validation logic for auto-approving kubelet-serving Certificate Signing Requests (CSRs).

    * `--provider-regex` or `PROVIDER_REGEX`: Regex to decide which hostnames can be approved (e.g., `^node-\w*\.int\.company\.ch$`).
    * `--max-expiration-sec` or `MAX_EXPIRATION_SEC`: Maximum `expirationSeconds` the kubelet can request. Defaults to a hardcoded 367 days if not specified.
    * `--bypass-dns-resolution` or `BYPASS_DNS_RESOLUTION`: Boolean (default `false`). If `true`, permits bypassing the DNS resolution check.
    * `--bypass-hostname-check` or `BYPASS_HOSTNAME_CHECK`: Boolean. When `true`, permits a DNS name that differs from the hostname.
    * `--provider-ip-prefixes` or `PROVIDER_IP_PREFIXES`: Comma-separated list of IP (v4/v6) subnets/prefixes. If unspecified, all IPs are allowed. Example: `192.168.0.0/16,fc00::/7`.
    * `--ignore-non-system-node` or `IGNORE_NON_SYSTEM_NODE`: Boolean (default `false`). If `true`, permits ignoring CSRs where the Username is not `system:node:......`.
    * `--allowed-dns-names` or `ALLOWED_DNS_NAMES`: Integer. Permits allowing more than one DNS name in the certificate request (default is `1`).
    * `--leader-election` or `LEADER_ELECTION`: Enables leader election when running multiple replicas.
  5. Configure kubelet-csr-approver parameters

    main

    The controller is configured via command-line flags or environment variables.

    ParameterEnv VarDescription
    --provider-regexPROVIDER_REGEXRegex to validate node hostnames (e.g., ^node-\w*\.int\.company\.ch$).
    --max-expiration-secMAX_EXPIRATION_SECMaximum allowed expirationSeconds. Defaults to 367 days.
    --bypass-dns-resolutionBYPASS_DNS_RESOLUTIONIf true, skips DNS resolution checks. Default is false.
    --bypass-hostname-checkBYPASS_HOSTNAME_CHECKIf true, permits DNS names that are not prefixed by the hostname.
    --provider-ip-prefixesPROVIDER_IP_PREFIXESComma-separated list of allowed IP subnets/prefixes (v4/v6).
    --ignore-non-system-nodeIGNORE_NON_SYSTEM_NODEIf true, allows CSRs where the Username is not prefixed with system:node:.
    --skip-deny-stepSKIP_DENY_STEPIf true, the controller only approves and never denies CSRs.
    --allowed-dns-namesALLOWED_DNS_NAMESNumber of DNS names allowed in the request. Default is 1.
    --leader-electionLEADER_ELECTIONEnables leader election for multiple replicas.
  6. Initialize the controller manager programmatically

    main

    If you are integrating or extending the controller, you can use CreateControllerManager to initialize the CertificateSigningRequestReconciler and the controller-runtime Manager.

    This function performs several critical setup steps:

    1. Validates the RegexStr configuration.
    2. Parses the IPPrefixesStr into a valid IPSet.
    3. Configures the controller-runtime Manager with metrics, health probes, and leader election settings.
    4. Automatically sets the LeaderElectionNamespace to kube-system if running outside of a cluster (detected via the absence of the service account namespace file).
    5. Sets up the healthz ping check.

    Returns the csrController, the mgr (Manager), and an error code (0 on success).

    // Example usage pattern for creating the manager
    csrController, mgr, errorCode := cmd.CreateControllerManager(config, logger)
    if errorCode != 0 {
        // handle error
    }
  7. Configure kubelet-csr-approver via CLI flags and environment variables

    main

    The kubelet-csr-approver can be configured using command-line flags or environment variables. The configuration determines how Certificate Signing Requests (CSRs) are validated, including regex matching for SAN names, IP prefix restrictions, and certificate expiration limits.

    Available Flags and Environment Variables

    FlagEnvironment VariableDefaultDescription
    --levelLEVEL0Log level from -5 (Fatal) to 10 (Verbose).
    --metrics-bind-addressMETRICS_BIND_ADDRESS:8080Address the metrics endpoint binds to.
    --health-probe-bind-addressHEALTH_PROBE_BIND_ADDRESS:8081Address the health probe endpoint binds to.
    --leader-electionLEADER_ELECTIONfalseEnable leader election.
    --provider-regexPROVIDER_REGEX.*Regex to validate CSR SAN names against.
    --max-expiration-secMAX_EXPIRATION_SEC31684800 (367 days)Maximum seconds a CSR can request a certificate for.
    --bypass-dns-resolutionBYPASS_DNS_RESOLUTIONfalseBypass DNS resolution checks.
    --bypass-hostname-checkBYPASS_HOSTNAME_CHECKfalseIgnore mismatching DNS name and hostname.
    --ignore-non-system-nodeIGNORE_NON_SYSTEM_NODEfalseIgnore CSRs for subjects different than system:node.
    --skip-deny-stepSKIP_DENY_STEPfalseSkip denying non-compliant CSRs.
    --allowed-dns-namesALLOWED_DNS_NAMES1Number of DNS SAN names allowed in a request (1-1000).
    --provider-ip-prefixesPROVIDER_IP_PREFIXES0.0.0.0/0,::/0Comma-separated IP prefixes that CSR IP addresses must fall into. Example: 192.168.0.0/16,fc00/7