mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-10-22 23:21:18 +00:00
Automatic merge from submit-queue (batch tested with PRs 64283, 67910, 67803, 68100). If you want to cherry-pick this change to another branch, please follow the instructions here: https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md. Kubeadm Cert Renewal **What this PR does / why we need it**: adds explicit support for renewal of certificates via command **Which issue(s) this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when PR gets merged)*: Fixes kubernetes/kubeadm#206 **Special notes for your reviewer**: The targeted documentation is at kubernetes/website#9712 **Release note**: ```release-note Adds the commands `kubeadm alpha phases renew <cert-name>` ```
233 lines
8.4 KiB
Go
233 lines
8.4 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package phases
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
|
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
|
|
kubeadmapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha3"
|
|
"k8s.io/kubernetes/cmd/kubeadm/app/cmd/options"
|
|
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
|
|
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
|
certsphase "k8s.io/kubernetes/cmd/kubeadm/app/phases/certs"
|
|
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
|
|
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
|
"k8s.io/kubernetes/pkg/util/normalizer"
|
|
)
|
|
|
|
var (
|
|
allCertsLongDesc = normalizer.LongDesc(`
|
|
Generates a self-signed CA to provision identities for each component in the cluster (including nodes)
|
|
and client certificates to be used by various components.
|
|
|
|
If a given certificate and private key pair both exist, kubeadm skips the generation step and
|
|
existing files will be used.
|
|
` + cmdutil.AlphaDisclaimer)
|
|
|
|
allCertsExample = normalizer.Examples(`
|
|
# Creates all PKI assets necessary to establish the control plane,
|
|
# functionally equivalent to what generated by kubeadm init.
|
|
kubeadm alpha phase certs all
|
|
|
|
# Creates all PKI assets using options read from a configuration file.
|
|
kubeadm alpha phase certs all --config masterconfiguration.yaml
|
|
`)
|
|
|
|
saKeyLongDesc = fmt.Sprintf(normalizer.LongDesc(`
|
|
Generates the private key for signing service account tokens along with its public key, and saves them into
|
|
%s and %s files.
|
|
If both files already exist, kubeadm skips the generation step and existing files will be used.
|
|
`+cmdutil.AlphaDisclaimer), kubeadmconstants.ServiceAccountPrivateKeyName, kubeadmconstants.ServiceAccountPublicKeyName)
|
|
|
|
genericLongDesc = normalizer.LongDesc(`
|
|
Generates the %[1]s, and saves them into %[2]s.cert and %[2]s.key files.%[3]s
|
|
|
|
If both files already exist, kubeadm skips the generation step and existing files will be used.
|
|
` + cmdutil.AlphaDisclaimer)
|
|
)
|
|
|
|
// NewCmdCerts returns main command for certs phase
|
|
func NewCmdCerts() *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "certs",
|
|
Aliases: []string{"certificates"},
|
|
Short: "Generates certificates for a Kubernetes cluster",
|
|
Long: cmdutil.MacroCommandLongDescription,
|
|
}
|
|
|
|
cmd.AddCommand(getCertsSubCommands("")...)
|
|
return cmd
|
|
}
|
|
|
|
// getCertsSubCommands returns sub commands for certs phase
|
|
func getCertsSubCommands(defaultKubernetesVersion string) []*cobra.Command {
|
|
|
|
cfg := &kubeadmapiv1alpha3.InitConfiguration{}
|
|
|
|
// Default values for the cobra help text
|
|
kubeadmscheme.Scheme.Default(cfg)
|
|
|
|
var cfgPath string
|
|
|
|
// Special case commands
|
|
// All runs CreatePKIAssets, which isn't a particular certificate
|
|
allCmd := &cobra.Command{
|
|
Use: "all",
|
|
Short: "Generates all PKI assets necessary to establish the control plane",
|
|
Long: allCertsLongDesc,
|
|
Example: allCertsExample,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
|
|
kubeadmutil.CheckErr(err)
|
|
|
|
err = certsphase.CreatePKIAssets(internalcfg)
|
|
kubeadmutil.CheckErr(err)
|
|
},
|
|
}
|
|
addFlags(allCmd, &cfgPath, cfg, true)
|
|
|
|
// SA creates the private/public key pair, which doesn't use x509 at all
|
|
saCmd := &cobra.Command{
|
|
Use: "sa",
|
|
Short: "Generates a private key for signing service account tokens along with its public key",
|
|
Long: saKeyLongDesc,
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(cfgPath, cfg)
|
|
kubeadmutil.CheckErr(err)
|
|
|
|
err = certsphase.CreateServiceAccountKeyAndPublicKeyFiles(internalcfg)
|
|
kubeadmutil.CheckErr(err)
|
|
},
|
|
}
|
|
addFlags(saCmd, &cfgPath, cfg, false)
|
|
|
|
subCmds := []*cobra.Command{allCmd, saCmd}
|
|
|
|
certTree, err := certsphase.GetDefaultCertList().AsMap().CertTree()
|
|
kubeadmutil.CheckErr(err)
|
|
|
|
for ca, certList := range certTree {
|
|
// Don't use pointers from for loops, they will be rewrittenb
|
|
caCmds := makeCommandsForCA(ca, certList, &cfgPath, cfg)
|
|
subCmds = append(subCmds, caCmds...)
|
|
}
|
|
|
|
return subCmds
|
|
}
|
|
|
|
func makeCmd(certSpec *certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: certSpec.Name,
|
|
Short: fmt.Sprintf("Generates the %s", certSpec.LongName),
|
|
Long: fmt.Sprintf(
|
|
genericLongDesc,
|
|
certSpec.LongName,
|
|
certSpec.BaseName,
|
|
getSANDescription(certSpec),
|
|
),
|
|
}
|
|
addFlags(cmd, cfgPath, cfg, certSpec.Name == "apiserver")
|
|
// Add flags to the command
|
|
return cmd
|
|
}
|
|
|
|
func getSANDescription(certSpec *certsphase.KubeadmCert) string {
|
|
//Defaulted config we will use to get SAN certs
|
|
defaultConfig := &kubeadmapiv1alpha3.InitConfiguration{
|
|
APIEndpoint: kubeadmapiv1alpha3.APIEndpoint{
|
|
// GetAPIServerAltNames errors without an AdvertiseAddress; this is as good as any.
|
|
AdvertiseAddress: "127.0.0.1",
|
|
},
|
|
}
|
|
defaultInternalConfig := &kubeadmapi.InitConfiguration{}
|
|
|
|
kubeadmscheme.Scheme.Default(defaultConfig)
|
|
kubeadmscheme.Scheme.Convert(defaultConfig, defaultInternalConfig, nil)
|
|
|
|
certConfig, err := certSpec.GetConfig(defaultInternalConfig)
|
|
kubeadmutil.CheckErr(err)
|
|
|
|
if len(certConfig.AltNames.DNSNames) == 0 && len(certConfig.AltNames.IPs) == 0 {
|
|
return ""
|
|
}
|
|
// This mutates the certConfig, but we're throwing it after we construct the command anyway
|
|
sans := []string{}
|
|
|
|
for _, dnsName := range certConfig.AltNames.DNSNames {
|
|
if dnsName != "" {
|
|
sans = append(sans, dnsName)
|
|
}
|
|
}
|
|
|
|
for _, ip := range certConfig.AltNames.IPs {
|
|
sans = append(sans, ip.String())
|
|
}
|
|
return fmt.Sprintf("\n\nDefault SANs are %s", strings.Join(sans, ", "))
|
|
}
|
|
|
|
func addFlags(cmd *cobra.Command, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration, addAPIFlags bool) {
|
|
options.AddCertificateDirFlag(cmd.Flags(), &cfg.CertificatesDir)
|
|
options.AddConfigFlag(cmd.Flags(), cfgPath)
|
|
if addAPIFlags {
|
|
cmd.Flags().StringVar(&cfg.Networking.DNSDomain, "service-dns-domain", cfg.Networking.DNSDomain, "Alternative domain for services, to use for the API server serving cert")
|
|
cmd.Flags().StringVar(&cfg.Networking.ServiceSubnet, "service-cidr", cfg.Networking.ServiceSubnet, "Alternative range of IP address for service VIPs, from which derives the internal API server VIP that will be added to the API Server serving cert")
|
|
cmd.Flags().StringSliceVar(&cfg.APIServerCertSANs, "apiserver-cert-extra-sans", []string{}, "Optional extra altnames to use for the API server serving cert. Can be both IP addresses and DNS names")
|
|
cmd.Flags().StringVar(&cfg.APIEndpoint.AdvertiseAddress, "apiserver-advertise-address", cfg.APIEndpoint.AdvertiseAddress, "The IP address the API server is accessible on, to use for the API server serving cert")
|
|
}
|
|
}
|
|
|
|
func makeCommandsForCA(ca *certsphase.KubeadmCert, certList []*certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) []*cobra.Command {
|
|
subCmds := []*cobra.Command{}
|
|
|
|
caCmd := makeCmd(ca, cfgPath, cfg)
|
|
caCmd.Run = func(cmd *cobra.Command, args []string) {
|
|
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg)
|
|
kubeadmutil.CheckErr(err)
|
|
|
|
err = certsphase.CreateCACertAndKeyFiles(ca, internalcfg)
|
|
kubeadmutil.CheckErr(err)
|
|
}
|
|
|
|
subCmds = append(subCmds, caCmd)
|
|
|
|
for _, cert := range certList {
|
|
certCmd := makeCommandForCert(cert, ca, cfgPath, cfg)
|
|
subCmds = append(subCmds, certCmd)
|
|
}
|
|
|
|
return subCmds
|
|
}
|
|
|
|
func makeCommandForCert(cert *certsphase.KubeadmCert, caCert *certsphase.KubeadmCert, cfgPath *string, cfg *kubeadmapiv1alpha3.InitConfiguration) *cobra.Command {
|
|
certCmd := makeCmd(cert, cfgPath, cfg)
|
|
|
|
certCmd.Run = func(cmd *cobra.Command, args []string) {
|
|
internalcfg, err := configutil.ConfigFileAndDefaultsToInternalConfig(*cfgPath, cfg)
|
|
kubeadmutil.CheckErr(err)
|
|
|
|
err = certsphase.CreateCertAndKeyFilesWithCA(cert, caCert, internalcfg)
|
|
kubeadmutil.CheckErr(err)
|
|
}
|
|
|
|
return certCmd
|
|
}
|