1
0
Fork 0
mirror of https://github.com/kubernetes-sigs/node-feature-discovery.git synced 2025-03-16 05:18:19 +00:00

Accept client certs based on SAN, not just CN (#514)

* first attempt at SAN-based VerifyNodeName

* Update docs on verify-node-name

(cherry picked from commit 77bd4e4cf6)
This commit is contained in:
robertdavidsmith 2021-04-20 09:44:32 +01:00 committed by Markus Lehtonen
parent 3a9c7203f4
commit bcd8775b5b
7 changed files with 27 additions and 19 deletions

View file

@ -103,7 +103,7 @@ func initFlags(flagset *flag.FlagSet) *master.Args {
flagset.Var(&args.ResourceLabels, "resource-labels", flagset.Var(&args.ResourceLabels, "resource-labels",
"Comma separated list of labels to be exposed as extended resources.") "Comma separated list of labels to be exposed as extended resources.")
flagset.BoolVar(&args.VerifyNodeName, "verify-node-name", false, flagset.BoolVar(&args.VerifyNodeName, "verify-node-name", false,
"Verify worker node name against CN from the TLS certificate. "+ "Verify worker node name against the worker's TLS certificate. "+
"Only takes effect when TLS authentication has been enabled.") "Only takes effect when TLS authentication has been enabled.")
return args return args

View file

@ -53,7 +53,7 @@ spec:
## a ConfigMap named nfd-ca-cert, and, the TLS authentication credentials stored ## a ConfigMap named nfd-ca-cert, and, the TLS authentication credentials stored
## in a TLS Secret named nfd-master-cert. ## in a TLS Secret named nfd-master-cert.
## Additional hardening can be enabled by specifying --verify-node-name in ## Additional hardening can be enabled by specifying --verify-node-name in
## args, in which case every nfd-worker requires a individual node-specific ## args, in which case node name will be checked against the worker's
## TLS certificate. ## TLS certificate.
# - "--ca-file=/etc/kubernetes/node-feature-discovery/trust/ca.crt" # - "--ca-file=/etc/kubernetes/node-feature-discovery/trust/ca.crt"
# - "--key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" # - "--key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key"

View file

@ -196,7 +196,7 @@ Usage of nfd-master:
-resource-labels value -resource-labels value
Comma separated list of labels to be exposed as extended resources. Comma separated list of labels to be exposed as extended resources.
-verify-node-name -verify-node-name
Verify worker node name against CN from the TLS certificate. Only takes effect when TLS authentication has been enabled. Verify worker node name against the worker's TLS certificate. Only takes effect when TLS authentication has been enabled.
-version -version
Print version and exit. Print version and exit.
``` ```

View file

@ -124,14 +124,11 @@ nfd-master -key-file=/opt/nfd/master.key -cert-file=/opt/nfd/master.crt -ca-file
The `-verify-node-name` flag controls the NodeName based authorization of The `-verify-node-name` flag controls the NodeName based authorization of
incoming requests and only has effect when mTLS authentication has been enabled incoming requests and only has effect when mTLS authentication has been enabled
(with `-ca-file`, `-cert-file` and `-key-file`). If enabled, the worker node (with `-ca-file`, `-cert-file` and `-key-file`). If enabled, the worker node
name of the incoming must match with the CN in its TLS certificate. Thus, name of the incoming must match with the CN or a SAN in its TLS certificate. Thus,
workers are only able to label the node they are running on (or the node whose workers are only able to label the node they are running on (or the node whose
certificate they present), and, each worker must have an individual certificate they present).
certificate.
Node Name based authorization is disabled by default and thus it is possible Node Name based authorization is disabled by default.
for all nfd-worker pods in the cluster to use one shared certificate, making
NFD deployment much easier.
Default: *false* Default: *false*

View file

@ -310,8 +310,8 @@ the nfd-master Service of the cluster. By default, nfd-master only check that
the nfd-worker has been signed by the specified root certificate (-ca-file). the nfd-worker has been signed by the specified root certificate (-ca-file).
Additional hardening can be enabled by specifying -verify-node-name in Additional hardening can be enabled by specifying -verify-node-name in
nfd-master args, in which case nfd-master verifies that the NodeName presented nfd-master args, in which case nfd-master verifies that the NodeName presented
by nfd-worker matches the Common Name (CN) of its certificate. This means that by nfd-worker matches the Common Name (CN) or a Subject Alternative Name (SAN)
each nfd-worker requires a individual node-specific TLS certificate. of its certificate.
#### Automated TLS certificate management using cert-manager #### Automated TLS certificate management using cert-manager
@ -334,9 +334,6 @@ $ kubectl apply -f nfd-cert-manager.yaml
Finally, deploy `nfd-master.yaml` and `nfd-worker-daemonset.yaml` with the Secrets Finally, deploy `nfd-master.yaml` and `nfd-worker-daemonset.yaml` with the Secrets
(`nfd-master-cert` and `nfd-worker-cert`) mounts enabled. (`nfd-master-cert` and `nfd-worker-cert`) mounts enabled.
**Note:** the automated setup to support `--verify-node-name` hardening cannot
be configured currently.
## Worker configuration ## Worker configuration
NFD-Worker supports dynamic configuration through a configuration file. The NFD-Worker supports dynamic configuration through a configuration file. The

View file

@ -97,7 +97,7 @@ spec:
## the TLS authentication credentials and a root certificate named ca.crt created. ## the TLS authentication credentials and a root certificate named ca.crt created.
## cert-manager can be used to automate the Secret creation and updates. ## cert-manager can be used to automate the Secret creation and updates.
## Additional hardening can be enabled by specifying --verify-node-name in ## Additional hardening can be enabled by specifying --verify-node-name in
## args, in which case every nfd-worker requires a individual node-specific ## args, in which case node name will be checked against the worker's
## TLS certificate. ## TLS certificate.
# args: # args:
# - "--ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" # - "--ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt"

View file

@ -18,6 +18,7 @@ package nfdmaster
import ( import (
"crypto/tls" "crypto/tls"
"crypto/x509"
"fmt" "fmt"
"net" "net"
"os" "os"
@ -347,6 +348,18 @@ func filterFeatureLabels(labels Labels, extraLabelNs map[string]struct{}, labelW
return outLabels, extendedResources return outLabels, extendedResources
} }
func verifyNodeName(cert *x509.Certificate, nodeName string) error {
if cert.Subject.CommonName == nodeName {
return nil
}
err := cert.VerifyHostname(nodeName)
if err != nil {
return fmt.Errorf("Certificate %q not valid for node %q: %v", cert.Subject.CommonName, nodeName, err)
}
return nil
}
// SetLabels implements LabelerServer // SetLabels implements LabelerServer
func (m *nfdMaster) SetLabels(c context.Context, r *pb.SetLabelsRequest) (*pb.SetLabelsReply, error) { func (m *nfdMaster) SetLabels(c context.Context, r *pb.SetLabelsRequest) (*pb.SetLabelsReply, error) {
if m.args.VerifyNodeName { if m.args.VerifyNodeName {
@ -366,10 +379,11 @@ func (m *nfdMaster) SetLabels(c context.Context, r *pb.SetLabelsRequest) (*pb.Se
klog.Errorf("gRPC request error: client certificate verification for '%v' failed", client.Addr) klog.Errorf("gRPC request error: client certificate verification for '%v' failed", client.Addr)
return &pb.SetLabelsReply{}, fmt.Errorf("client certificate verification failed") return &pb.SetLabelsReply{}, fmt.Errorf("client certificate verification failed")
} }
cn := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName
if cn != r.NodeName { err := verifyNodeName(tlsAuth.State.VerifiedChains[0][0], r.NodeName)
klog.Errorf("gRPC request error: authorization for %v failed: cert valid for %q, requested node name %q", client.Addr, cn, r.NodeName) if err != nil {
return &pb.SetLabelsReply{}, fmt.Errorf("request authorization failed: cert valid for %q, requested node name %q", cn, r.NodeName) klog.Errorf("gRPC request error: authorization for %v failed: %v", client.Addr, err)
return &pb.SetLabelsReply{}, err
} }
} }
if klog.V(1).Enabled() { if klog.V(1).Enabled() {