Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kube-apiserver: split apart generic control plane options #118633

Merged
merged 3 commits into from Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/kube-apiserver/app/aggregator.go
Expand Up @@ -47,13 +47,13 @@ import (
apiregistrationclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/typed/apiregistration/v1"
informers "k8s.io/kube-aggregator/pkg/client/informers/externalversions/apiregistration/v1"
"k8s.io/kube-aggregator/pkg/controllers/autoregister"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
controlplaneapiserver "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
"k8s.io/kubernetes/pkg/controlplane/controller/crdregistration"
)

func createAggregatorConfig(
kubeAPIServerConfig genericapiserver.Config,
commandOptions *options.ServerRunOptions,
commandOptions controlplaneapiserver.CompletedOptions,
externalInformers kubeexternalinformers.SharedInformerFactory,
serviceResolver aggregatorapiserver.ServiceResolver,
proxyTransport *http.Transport,
Expand Down
4 changes: 2 additions & 2 deletions cmd/kube-apiserver/app/config.go
Expand Up @@ -77,14 +77,14 @@ func NewConfig(opts options.CompletedOptions) (*Config, error) {
}
c.ControlPlane = controlPlane

apiExtensions, err := apiserver.CreateAPIExtensionsConfig(*controlPlane.GenericConfig, controlPlane.ExtraConfig.VersionedInformers, pluginInitializer, opts.ServerRunOptions, opts.MasterCount,
apiExtensions, err := apiserver.CreateAPIExtensionsConfig(*controlPlane.GenericConfig, controlPlane.ExtraConfig.VersionedInformers, pluginInitializer, opts.CompletedOptions, opts.MasterCount,
serviceResolver, webhook.NewDefaultAuthenticationInfoResolverWrapper(controlPlane.ExtraConfig.ProxyTransport, controlPlane.GenericConfig.EgressSelector, controlPlane.GenericConfig.LoopbackClientConfig, controlPlane.GenericConfig.TracerProvider))
if err != nil {
return nil, err
}
c.ApiExtensions = apiExtensions

aggregator, err := createAggregatorConfig(*controlPlane.GenericConfig, opts.ServerRunOptions, controlPlane.ExtraConfig.VersionedInformers, serviceResolver, controlPlane.ExtraConfig.ProxyTransport, pluginInitializer)
aggregator, err := createAggregatorConfig(*controlPlane.GenericConfig, opts.CompletedOptions, controlPlane.ExtraConfig.VersionedInformers, serviceResolver, controlPlane.ExtraConfig.ProxyTransport, pluginInitializer)
if err != nil {
return nil, err
}
Expand Down
121 changes: 29 additions & 92 deletions cmd/kube-apiserver/app/options/completion.go
Expand Up @@ -19,141 +19,78 @@ package options
import (
"fmt"
"net"
"os"
"strings"
"time"

serveroptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/client-go/util/keyutil"
apiserveroptions "k8s.io/apiserver/pkg/server/options"
_ "k8s.io/component-base/metrics/prometheus/workqueue"
"k8s.io/klog/v2"
netutils "k8s.io/utils/net"

"k8s.io/kubernetes/pkg/controlplane"
controlplane "k8s.io/kubernetes/pkg/controlplane/apiserver/options"
"k8s.io/kubernetes/pkg/kubeapiserver"
kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator"
"k8s.io/kubernetes/pkg/serviceaccount"
kubeoptions "k8s.io/kubernetes/pkg/kubeapiserver/options"
)

// completedOptions is a private wrapper that enforces a call of Complete() before Run can be invoked.
type completedOptions struct {
*ServerRunOptions
controlplane.CompletedOptions
CloudProvider *kubeoptions.CloudProviderOptions

Extra
dims marked this conversation as resolved.
Show resolved Hide resolved
}

type CompletedOptions struct {
completedOptions
// Embed a private pointer that cannot be instantiated outside of this package.
*completedOptions
}

// Complete set default ServerRunOptions.
// Should be called after kube-apiserver flags parsed.
func Complete(opts *ServerRunOptions) (CompletedOptions, error) {
// set defaults
if err := opts.GenericServerRunOptions.DefaultAdvertiseAddress(opts.SecureServing.SecureServingOptions); err != nil {
return CompletedOptions{}, err
func (opts *ServerRunOptions) Complete() (CompletedOptions, error) {
if opts == nil {
return CompletedOptions{completedOptions: &completedOptions{}}, nil
}

// process s.ServiceClusterIPRange from list to Primary and Secondary
// process opts.ServiceClusterIPRange from list to Primary and Secondary
// we process secondary only if provided by user
apiServerServiceIP, primaryServiceIPRange, secondaryServiceIPRange, err := getServiceIPAndRanges(opts.ServiceClusterIPRanges)
if err != nil {
return CompletedOptions{}, err
}
opts.PrimaryServiceClusterIPRange = primaryServiceIPRange
opts.SecondaryServiceClusterIPRange = secondaryServiceIPRange
opts.APIServerServiceIP = apiServerServiceIP

if err := opts.SecureServing.MaybeDefaultWithSelfSignedCerts(opts.GenericServerRunOptions.AdvertiseAddress.String(), []string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}, []net.IP{apiServerServiceIP}); err != nil {
return CompletedOptions{}, fmt.Errorf("error creating self-signed certificates: %v", err)
controlplane, err := opts.Options.Complete([]string{"kubernetes.default.svc", "kubernetes.default", "kubernetes"}, []net.IP{apiServerServiceIP})
if err != nil {
return CompletedOptions{}, err
}

if len(opts.GenericServerRunOptions.ExternalHost) == 0 {
if len(opts.GenericServerRunOptions.AdvertiseAddress) > 0 {
opts.GenericServerRunOptions.ExternalHost = opts.GenericServerRunOptions.AdvertiseAddress.String()
} else {
hostname, err := os.Hostname()
if err != nil {
return CompletedOptions{}, fmt.Errorf("error finding host name: %v", err)
}
opts.GenericServerRunOptions.ExternalHost = hostname
}
klog.Infof("external host was not specified, using %v", opts.GenericServerRunOptions.ExternalHost)
}
completed := completedOptions{
CompletedOptions: controlplane,
CloudProvider: opts.CloudProvider,

opts.Authentication.ApplyAuthorization(opts.Authorization)

// Use (ServiceAccountSigningKeyFile != "") as a proxy to the user enabling
// TokenRequest functionality. This defaulting was convenient, but messed up
// a lot of people when they rotated their serving cert with no idea it was
// connected to their service account keys. We are taking this opportunity to
// remove this problematic defaulting.
if opts.ServiceAccountSigningKeyFile == "" {
// Default to the private server key for service account token signing
if len(opts.Authentication.ServiceAccounts.KeyFiles) == 0 && opts.SecureServing.ServerCert.CertKey.KeyFile != "" {
if kubeauthenticator.IsValidServiceAccountKeyFile(opts.SecureServing.ServerCert.CertKey.KeyFile) {
opts.Authentication.ServiceAccounts.KeyFiles = []string{opts.SecureServing.ServerCert.CertKey.KeyFile}
} else {
klog.Warning("No TLS key provided, service account token authentication disabled")
}
}
Extra: opts.Extra,
}

if opts.ServiceAccountSigningKeyFile != "" && len(opts.Authentication.ServiceAccounts.Issuers) != 0 && opts.Authentication.ServiceAccounts.Issuers[0] != "" {
sk, err := keyutil.PrivateKeyFromFile(opts.ServiceAccountSigningKeyFile)
if err != nil {
return CompletedOptions{}, fmt.Errorf("failed to parse service-account-issuer-key-file: %v", err)
}
if opts.Authentication.ServiceAccounts.MaxExpiration != 0 {
lowBound := time.Hour
upBound := time.Duration(1<<32) * time.Second
if opts.Authentication.ServiceAccounts.MaxExpiration < lowBound ||
opts.Authentication.ServiceAccounts.MaxExpiration > upBound {
return CompletedOptions{}, fmt.Errorf("the service-account-max-token-expiration must be between 1 hour and 2^32 seconds")
}
if opts.Authentication.ServiceAccounts.ExtendExpiration {
if opts.Authentication.ServiceAccounts.MaxExpiration < serviceaccount.WarnOnlyBoundTokenExpirationSeconds*time.Second {
klog.Warningf("service-account-extend-token-expiration is true, in order to correctly trigger safe transition logic, service-account-max-token-expiration must be set longer than %d seconds (currently %s)", serviceaccount.WarnOnlyBoundTokenExpirationSeconds, opts.Authentication.ServiceAccounts.MaxExpiration)
}
if opts.Authentication.ServiceAccounts.MaxExpiration < serviceaccount.ExpirationExtensionSeconds*time.Second {
klog.Warningf("service-account-extend-token-expiration is true, enabling tokens valid up to %d seconds, which is longer than service-account-max-token-expiration set to %s seconds", serviceaccount.ExpirationExtensionSeconds, opts.Authentication.ServiceAccounts.MaxExpiration)
}
}
}

opts.ServiceAccountIssuer, err = serviceaccount.JWTTokenGenerator(opts.Authentication.ServiceAccounts.Issuers[0], sk)
if err != nil {
return CompletedOptions{}, fmt.Errorf("failed to build token generator: %v", err)
}
opts.ServiceAccountTokenMaxExpiration = opts.Authentication.ServiceAccounts.MaxExpiration
}
completed.PrimaryServiceClusterIPRange = primaryServiceIPRange
completed.SecondaryServiceClusterIPRange = secondaryServiceIPRange
completed.APIServerServiceIP = apiServerServiceIP

if opts.Etcd.EnableWatchCache {
if completed.Etcd != nil && completed.Etcd.EnableWatchCache {
sizes := kubeapiserver.DefaultWatchCacheSizes()
// Ensure that overrides parse correctly.
userSpecified, err := serveroptions.ParseWatchCacheSizes(opts.Etcd.WatchCacheSizes)
userSpecified, err := apiserveroptions.ParseWatchCacheSizes(completed.Etcd.WatchCacheSizes)
if err != nil {
return CompletedOptions{}, err
}
for resource, size := range userSpecified {
sizes[resource] = size
}
opts.Etcd.WatchCacheSizes, err = serveroptions.WriteWatchCacheSizes(sizes)
completed.Etcd.WatchCacheSizes, err = apiserveroptions.WriteWatchCacheSizes(sizes)
if err != nil {
return CompletedOptions{}, err
}
}

for key, value := range opts.APIEnablement.RuntimeConfig {
if key == "v1" || strings.HasPrefix(key, "v1/") ||
key == "api/v1" || strings.HasPrefix(key, "api/v1/") {
delete(opts.APIEnablement.RuntimeConfig, key)
opts.APIEnablement.RuntimeConfig["/v1"] = value
}
if key == "api/legacy" {
delete(opts.APIEnablement.RuntimeConfig, key)
}
}

return CompletedOptions{completedOptions: completedOptions{ServerRunOptions: opts}}, nil
return CompletedOptions{
completedOptions: &completed,
}, nil
}

func getServiceIPAndRanges(serviceClusterIPRanges string) (net.IP, net.IPNet, net.IPNet, error) {
Expand Down