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:
parent
3a9c7203f4
commit
bcd8775b5b
7 changed files with 27 additions and 19 deletions
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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.
|
||||||
```
|
```
|
||||||
|
|
|
@ -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*
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue