mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 04:33:26 +00:00
Merge pull request #125813 from aojea/node_csr_ips
Node Request Certificates require to have IPs
This commit is contained in:
commit
fa7fcde5a4
@ -45,6 +45,13 @@ const (
|
||||
// Enable usage of Provision of PVCs from snapshots in other namespaces
|
||||
CrossNamespaceVolumeDataSource featuregate.Feature = "CrossNamespaceVolumeDataSource"
|
||||
|
||||
// owner: @aojea
|
||||
// Deprecated: v1.31
|
||||
//
|
||||
// Allow kubelet to request a certificate without any Node IP available, only
|
||||
// with DNS names.
|
||||
AllowDNSOnlyNodeCSR featuregate.Feature = "AllowDNSOnlyNodeCSR"
|
||||
|
||||
// owner: @thockin
|
||||
// deprecated: v1.29
|
||||
//
|
||||
@ -991,6 +998,8 @@ func init() {
|
||||
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
|
||||
CrossNamespaceVolumeDataSource: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
||||
AllowDNSOnlyNodeCSR: {Default: false, PreRelease: featuregate.Deprecated}, // remove after 1.33
|
||||
|
||||
AllowServiceLBStatusOnNonLB: {Default: false, PreRelease: featuregate.Deprecated}, // remove after 1.29
|
||||
|
||||
AnyVolumeDataSource: {Default: true, PreRelease: featuregate.Beta}, // on by default in 1.24
|
||||
|
@ -32,16 +32,44 @@ import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apiserver/pkg/server/dynamiccertificates"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/util/certificate"
|
||||
compbasemetrics "k8s.io/component-base/metrics"
|
||||
"k8s.io/component-base/metrics/legacyregistry"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||
"k8s.io/kubernetes/pkg/kubelet/metrics"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
func newGetTemplateFn(nodeName types.NodeName, getAddresses func() []v1.NodeAddress) func() *x509.CertificateRequest {
|
||||
return func() *x509.CertificateRequest {
|
||||
hostnames, ips := addressesToHostnamesAndIPs(getAddresses())
|
||||
// by default, require at least one IP before requesting a serving certificate
|
||||
hasRequiredAddresses := len(ips) > 0
|
||||
|
||||
// optionally allow requesting a serving certificate with just a DNS name
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.AllowDNSOnlyNodeCSR) {
|
||||
hasRequiredAddresses = hasRequiredAddresses || len(hostnames) > 0
|
||||
}
|
||||
|
||||
// don't return a template if we have no addresses to request for
|
||||
if !hasRequiredAddresses {
|
||||
return nil
|
||||
}
|
||||
return &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
DNSNames: hostnames,
|
||||
IPAddresses: ips,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewKubeletServerCertificateManager creates a certificate manager for the kubelet when retrieving a server certificate
|
||||
// or returns an error.
|
||||
func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg *kubeletconfig.KubeletConfiguration, nodeName types.NodeName, getAddresses func() []v1.NodeAddress, certDirectory string) (certificate.Manager, error) {
|
||||
@ -92,21 +120,7 @@ func NewKubeletServerCertificateManager(kubeClient clientset.Interface, kubeCfg
|
||||
)
|
||||
legacyregistry.MustRegister(certificateRotationAge)
|
||||
|
||||
getTemplate := func() *x509.CertificateRequest {
|
||||
hostnames, ips := addressesToHostnamesAndIPs(getAddresses())
|
||||
// don't return a template if we have no addresses to request for
|
||||
if len(hostnames) == 0 && len(ips) == 0 {
|
||||
return nil
|
||||
}
|
||||
return &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
DNSNames: hostnames,
|
||||
IPAddresses: ips,
|
||||
}
|
||||
}
|
||||
getTemplate := newGetTemplateFn(nodeName, getAddresses)
|
||||
|
||||
m, err := certificate.NewManager(&certificate.Config{
|
||||
ClientsetFn: clientsetFn,
|
||||
|
@ -19,6 +19,8 @@ package certificate
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
@ -28,8 +30,12 @@ import (
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/util/cert"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
@ -261,3 +267,142 @@ func TestKubeletServerCertificateFromFiles(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewCertificateManagerConfigGetTemplate(t *testing.T) {
|
||||
nodeName := "fake-node"
|
||||
nodeIP := netutils.ParseIPSloppy("192.168.1.1")
|
||||
tests := []struct {
|
||||
name string
|
||||
nodeAddresses []v1.NodeAddress
|
||||
want *x509.CertificateRequest
|
||||
featuregate bool
|
||||
}{
|
||||
{
|
||||
name: "node addresses or hostnames and gate enabled",
|
||||
featuregate: true,
|
||||
},
|
||||
{
|
||||
name: "node addresses or hostnames and gate disabled",
|
||||
featuregate: false,
|
||||
},
|
||||
{
|
||||
name: "only hostnames and gate enabled",
|
||||
nodeAddresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeHostName,
|
||||
Address: nodeName,
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
DNSNames: []string{nodeName},
|
||||
},
|
||||
featuregate: true,
|
||||
},
|
||||
{
|
||||
name: "only hostnames and gate disabled",
|
||||
nodeAddresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeHostName,
|
||||
Address: nodeName,
|
||||
},
|
||||
},
|
||||
featuregate: false,
|
||||
},
|
||||
{
|
||||
name: "only IP addresses and gate enabled",
|
||||
nodeAddresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: nodeIP.String(),
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
IPAddresses: []net.IP{nodeIP},
|
||||
},
|
||||
featuregate: true,
|
||||
},
|
||||
{
|
||||
name: "only IP addresses and gate disabled",
|
||||
nodeAddresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: nodeIP.String(),
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
IPAddresses: []net.IP{nodeIP},
|
||||
},
|
||||
featuregate: false,
|
||||
},
|
||||
{
|
||||
name: "IP addresses and hostnames and gate enabled",
|
||||
nodeAddresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeHostName,
|
||||
Address: nodeName,
|
||||
},
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: nodeIP.String(),
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
DNSNames: []string{nodeName},
|
||||
IPAddresses: []net.IP{nodeIP},
|
||||
},
|
||||
featuregate: true,
|
||||
},
|
||||
{
|
||||
name: "IP addresses and hostnames and gate disabled",
|
||||
nodeAddresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeHostName,
|
||||
Address: nodeName,
|
||||
},
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: nodeIP.String(),
|
||||
},
|
||||
},
|
||||
want: &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("system:node:%s", nodeName),
|
||||
Organization: []string{"system:nodes"},
|
||||
},
|
||||
DNSNames: []string{nodeName},
|
||||
IPAddresses: []net.IP{nodeIP},
|
||||
},
|
||||
featuregate: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.AllowDNSOnlyNodeCSR, tt.featuregate)
|
||||
getAddresses := func() []v1.NodeAddress {
|
||||
return tt.nodeAddresses
|
||||
}
|
||||
getTemplate := newGetTemplateFn(types.NodeName(nodeName), getAddresses)
|
||||
got := getTemplate()
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Wrong certificate, got %v expected %v", got, tt.want)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user