Skip to content

Commit

Permalink
Add support for specifying vsphere credentials via secrets (#250)
Browse files Browse the repository at this point in the history
- Adds new field vsphereCredentialSecret that can be specified to
  point to the secret that holds the credentials

Resolves #9

Change-Id: I8e43864302a51386f7f11725b0a966cc9e436c59
  • Loading branch information
sidharthsurana authored and k8s-ci-robot committed Apr 19, 2019
1 parent e1a0555 commit b5ce311
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 7 deletions.
3 changes: 2 additions & 1 deletion cmd/clusterctl/examples/vsphere/cluster.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ spec:
kind: "VsphereClusterProviderConfig"
vsphereUser: ""
vspherePassword: ""
vsphereServer: ""
vsphereServer: ""
vsphereCredentialSecret: ""
49 changes: 49 additions & 0 deletions docs/design/vsphereCredentials.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## Passing vsphere credentials
For the cluster-api vsphere provider to work, the users need to provide the vsphere credentials to access the infrastructure. There are 2 ways how the users can provide these credentials.

* Using kubernetes `secrets`
* Create a secret that contains 2 keys namely `username` and `password` in the same namespace as the desired `Cluster` object.
```
apiVersion: v1
kind: Secret
metadata:
name: my-vc-credentials
type: Opaque
data:
# base64 encoded fields
username: YWRtaW5pc3RyYXRvckB2c3BoZXJlLmxvY2Fs
password: c2FtcGxl
```

* Set the `vsphereCredentialSecret` property in the `ProviderSpec` part of the `Cluster` definition
```
apiVersion: "cluster.k8s.io/v1alpha1"
kind: Cluster
metadata:
name: sample-cluster
spec:
...
providerSpec:
value:
...
# Credentials provided via secrets
vsphereCredentialSecret: "my-vc-credentials"
```

* Using plain text credential in the `ProviderSpec` part of the `Cluster` definition
```
apiVersion: "cluster.k8s.io/v1alpha1"
kind: Cluster
metadata:
name: sample-cluster
spec:
...
providerSpec:
value:
...
# Credentials provided as plain text
vsphereUser: "administrator@vsphere.local"
vspherePassword: "sample"
```

__Note:__ If `vsphereCredentialSecret` field is set to a non empty string then the controller will ignore the `vsphereUser` and `vspherePassword` fields even if they are set.
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ type VsphereClusterProviderConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

VsphereUser string `json:"vsphereUser"`
VspherePassword string `json:"vspherePassword"`
VsphereServer string `json:"vsphereServer"`
VsphereUser string `json:"vsphereUser"`
VspherePassword string `json:"vspherePassword"`
VsphereServer string `json:"vsphereServer"`
VsphereCredentialSecret string `json:"vsphereCredentialSecret"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
Expand Down
2 changes: 2 additions & 0 deletions pkg/cloud/vsphere/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ const (
RequeueAfterSeconds = 20 * time.Second
KubeConfigSecretName = "%s-kubeconfig"
KubeConfigSecretData = "admin-kubeconfig"
VsphereUserKey = "username"
VspherePasswordKey = "password"
ClusterIsNullErr = "cluster is nil, make sure machines have `clusters.k8s.io/cluster-name` label set and the name references a valid cluster name in the same namespace"
)
10 changes: 7 additions & 3 deletions pkg/cloud/vsphere/provisioner/govmomi/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ func (pv *Provisioner) sessionFromProviderConfig(cluster *clusterv1.Cluster, mac
if err != nil {
return nil, err
}
if ses, ok := pv.sessioncache[vsphereConfig.VsphereServer+vsphereConfig.VsphereUser]; ok {
username, password, err := pv.GetVsphereCredentials(cluster)
if err != nil {
return nil, err
}
if ses, ok := pv.sessioncache[vsphereConfig.VsphereServer+username]; ok {
s, ok := ses.(SessionContext)
if ok {
// Test if the session is valid and return
Expand All @@ -41,7 +45,7 @@ func (pv *Provisioner) sessionFromProviderConfig(cluster *clusterv1.Cluster, mac
return nil, fmt.Errorf("error parsing vSphere URL %s : [%s]", soapURL, err)
}
// Set the credentials
soapURL.User = url.UserPassword(vsphereConfig.VsphereUser, vsphereConfig.VspherePassword)
soapURL.User = url.UserPassword(username, password)
// Temporarily setting the insecure flag True
// TODO(ssurana): handle the certs better
sc.session, err = govmomi.NewClient(ctx, soapURL, true)
Expand All @@ -51,6 +55,6 @@ func (pv *Provisioner) sessionFromProviderConfig(cluster *clusterv1.Cluster, mac
sc.context = &ctx
finder := find.NewFinder(sc.session.Client, false)
sc.finder = finder
pv.sessioncache[vsphereConfig.VsphereServer+vsphereConfig.VsphereUser] = sc
pv.sessioncache[vsphereConfig.VsphereServer+username] = sc
return &sc, nil
}
24 changes: 24 additions & 0 deletions pkg/cloud/vsphere/provisioner/govmomi/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,27 @@ func (pv *Provisioner) GetKubeConfig(cluster *clusterv1.Cluster) (string, error)
}
return string(secret.Data[constants.KubeConfigSecretData]), nil
}

func (pv *Provisioner) GetVsphereCredentials(cluster *clusterv1.Cluster) (string, string, error) {
vsphereConfig, err := vsphereutils.GetClusterProviderSpec(cluster.Spec.ProviderSpec)
if err != nil {
return "", "", err
}
// If the vsphereCredentialSecret is specified then read that secret to get the credentials
if vsphereConfig.VsphereCredentialSecret != "" {
klog.V(4).Infof("Fetching vsphere credentials from secret %s", vsphereConfig.VsphereCredentialSecret)
secret, err := pv.k8sClient.Core().Secrets(cluster.Namespace).Get(vsphereConfig.VsphereCredentialSecret, metav1.GetOptions{})
if err != nil {
klog.Warningf("Error reading secret %s", vsphereConfig.VsphereCredentialSecret)
return "", "", err
}
if username, ok := secret.Data[constants.VsphereUserKey]; ok {
if password, ok := secret.Data[constants.VspherePasswordKey]; ok {
return string(username), string(password), nil
}
}
return "", "", fmt.Errorf("Improper secret: Secret %s should have the keys `%s` and `%s` defined in it", vsphereConfig.VsphereCredentialSecret, constants.VsphereUserKey, constants.VspherePasswordKey)
}
return vsphereConfig.VsphereUser, vsphereConfig.VspherePassword, nil

}

0 comments on commit b5ce311

Please sign in to comment.