mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 22:46:12 +00:00
Allow to read OpenStack config from the secret
Currently OpenStack cloud provider reads user credentials from config file, where data is stored in clear text. This approach is not recommended, as it is a serious security issue. This commit add an ability to read the config from secrets, if necessary. To do so, two new parameters are added to the config: SecretNamespace and SecretName. If they are specified, the provider will try to read config from the secret.
This commit is contained in:
parent
baf4eb67ac
commit
cf8c193b87
@ -23,10 +23,13 @@ go_library(
|
||||
"//pkg/util/mount:go_default_library",
|
||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider:go_default_library",
|
||||
"//staging/src/k8s.io/cloud-provider/node/helpers:go_default_library",
|
||||
|
@ -42,8 +42,11 @@ import (
|
||||
"gopkg.in/gcfg.v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
certutil "k8s.io/client-go/util/cert"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
nodehelpers "k8s.io/cloud-provider/node/helpers"
|
||||
@ -145,17 +148,19 @@ type OpenStack struct {
|
||||
// Config is used to read and store information from the cloud configuration file
|
||||
type Config struct {
|
||||
Global struct {
|
||||
AuthURL string `gcfg:"auth-url"`
|
||||
Username string
|
||||
UserID string `gcfg:"user-id"`
|
||||
Password string
|
||||
TenantID string `gcfg:"tenant-id"`
|
||||
TenantName string `gcfg:"tenant-name"`
|
||||
TrustID string `gcfg:"trust-id"`
|
||||
DomainID string `gcfg:"domain-id"`
|
||||
DomainName string `gcfg:"domain-name"`
|
||||
Region string
|
||||
CAFile string `gcfg:"ca-file"`
|
||||
AuthURL string `gcfg:"auth-url"`
|
||||
Username string
|
||||
UserID string `gcfg:"user-id"`
|
||||
Password string
|
||||
TenantID string `gcfg:"tenant-id"`
|
||||
TenantName string `gcfg:"tenant-name"`
|
||||
TrustID string `gcfg:"trust-id"`
|
||||
DomainID string `gcfg:"domain-id"`
|
||||
DomainName string `gcfg:"domain-name"`
|
||||
Region string
|
||||
CAFile string `gcfg:"ca-file"`
|
||||
SecretName string `gcfg:"secret-name"`
|
||||
SecretNamespace string `gcfg:"secret-namespace"`
|
||||
}
|
||||
LoadBalancer LoadBalancerOpts
|
||||
BlockStorage BlockStorageOpts
|
||||
@ -231,6 +236,9 @@ func configFromEnv() (cfg Config, ok bool) {
|
||||
cfg.Global.DomainName = os.Getenv("OS_USER_DOMAIN_NAME")
|
||||
}
|
||||
|
||||
cfg.Global.SecretName = os.Getenv("SECRET_NAME")
|
||||
cfg.Global.SecretNamespace = os.Getenv("SECRET_NAMESPACE")
|
||||
|
||||
ok = cfg.Global.AuthURL != "" &&
|
||||
cfg.Global.Username != "" &&
|
||||
cfg.Global.Password != "" &&
|
||||
@ -245,6 +253,58 @@ func configFromEnv() (cfg Config, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func createKubernetesClient() (*kubernetes.Clientset, error) {
|
||||
klog.Info("Creating kubernetes API client.")
|
||||
|
||||
// create in-cluster config
|
||||
cfg, err := clientcmd.BuildConfigFromFlags("", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := kubernetes.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, err := client.Discovery().ServerVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.Infof("Kubernetes API client created, server version %s", fmt.Sprintf("v%v.%v", v.Major, v.Minor))
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// setConfigFromSecret allows setting up the config from k8s secret
|
||||
func setConfigFromSecret(cfg *Config) error {
|
||||
secretName := cfg.Global.SecretName
|
||||
secretNamespace := cfg.Global.SecretNamespace
|
||||
|
||||
k8sClient, err := createKubernetesClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get kubernetes client: %v", err)
|
||||
}
|
||||
|
||||
secret, err := k8sClient.CoreV1().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
klog.Warningf("Cannot get secret %s in namespace %s. error: %q", secretName, secretNamespace, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if content, ok := secret.Data["clouds.conf"]; ok {
|
||||
err = gcfg.ReadStringInto(cfg, string(content))
|
||||
if err != nil {
|
||||
klog.Errorf("Cannot parse data from the secret.")
|
||||
return fmt.Errorf("cannot parse data from the secret")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
klog.Errorf("Cannot find \"clouds.conf\" key in the secret.")
|
||||
return fmt.Errorf("cannot find \"clouds.conf\" key in the secret")
|
||||
}
|
||||
|
||||
func readConfig(config io.Reader) (Config, error) {
|
||||
if config == nil {
|
||||
return Config{}, fmt.Errorf("no OpenStack cloud provider config file given")
|
||||
@ -259,7 +319,19 @@ func readConfig(config io.Reader) (Config, error) {
|
||||
cfg.Metadata.SearchOrder = fmt.Sprintf("%s,%s", configDriveID, metadataID)
|
||||
|
||||
err := gcfg.ReadInto(&cfg, config)
|
||||
return cfg, err
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
if cfg.Global.SecretName != "" && cfg.Global.SecretNamespace != "" {
|
||||
klog.Infof("Set credentials from secret %s in namespace %s", cfg.Global.SecretName, cfg.Global.SecretNamespace)
|
||||
err = setConfigFromSecret(&cfg)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
}
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// caller is a tiny helper for conditional unwind logic
|
||||
|
@ -304,17 +304,19 @@ func getOpenstackCloudProvider() (*openstack.OpenStack, error) {
|
||||
func getOpenstackConfig() openstack.Config {
|
||||
cfg := openstack.Config{
|
||||
Global: struct {
|
||||
AuthURL string `gcfg:"auth-url"`
|
||||
Username string
|
||||
UserID string `gcfg:"user-id"`
|
||||
Password string
|
||||
TenantID string `gcfg:"tenant-id"`
|
||||
TenantName string `gcfg:"tenant-name"`
|
||||
TrustID string `gcfg:"trust-id"`
|
||||
DomainID string `gcfg:"domain-id"`
|
||||
DomainName string `gcfg:"domain-name"`
|
||||
Region string
|
||||
CAFile string `gcfg:"ca-file"`
|
||||
AuthURL string `gcfg:"auth-url"`
|
||||
Username string
|
||||
UserID string `gcfg:"user-id"`
|
||||
Password string
|
||||
TenantID string `gcfg:"tenant-id"`
|
||||
TenantName string `gcfg:"tenant-name"`
|
||||
TrustID string `gcfg:"trust-id"`
|
||||
DomainID string `gcfg:"domain-id"`
|
||||
DomainName string `gcfg:"domain-name"`
|
||||
Region string
|
||||
CAFile string `gcfg:"ca-file"`
|
||||
SecretName string `gcfg:"secret-name"`
|
||||
SecretNamespace string `gcfg:"secret-namespace"`
|
||||
}{
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
|
Loading…
Reference in New Issue
Block a user