Skip to content

Commit

Permalink
Support Gardener credentials data keys for Alicloud, AWS, Azure, GCP
Browse files Browse the repository at this point in the history
  • Loading branch information
rfranzke committed Nov 29, 2020
1 parent c5b351d commit 0e41070
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 25 deletions.
3 changes: 3 additions & 0 deletions kubernetes/Secrets/alicloud-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ data:
userData: "encoded-cloud-config" # Alicloud cloud config file (base64 encoded)
alicloudAccessKeyID: "alicloud-access-key-id" # Alicloud access key ID (base64 encoded)
alicloudAccessKeySecret: "alicloud-access-key-secret" # Alicloud secret access key (base64 encoded)
### Alternative data keys are:
# accessKeyID: "alicloud-access-key-id" # Alicloud access key ID (base64 encoded)
# accessKeySecret: "alicloud-access-key-secret" # Alicloud secret access key (base64 encoded)
type: Opaque
3 changes: 3 additions & 0 deletions kubernetes/Secrets/aws-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ data:
userData: "encoded-cloud-config" # AWS cloud config file (base64 encoded)
providerAccessKeyId: "pqrstu67890" # AWS access key id (base64 encoded)
providerSecretAccessKey: "abcdef123456" # AWS secret access key (base64 encoded)
### Alternative data keys are:
# accessKeyId: "pqrstu67890" # AWS access key id (base64 encoded)
# secretAccessKey: "abcdef123456" # AWS secret access key (base64 encoded)
type: Opaque
5 changes: 5 additions & 0 deletions kubernetes/Secrets/azure-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ data:
azureClientSecret: "azure-client-secret" # Azure client secret (base64 encoded)
azureSubscriptionId: "azure-subscription-id" # Azure subscription id (base64 encoded)
azureTenantId: "azure-tenant-id" # Azure tenant id (base64 encoded)
### Alternative data keys are:
# clientID: "azure-client-id" # Azure client id (base64 encoded)
# clientSecret: "azure-client-secret" # Azure client secret (base64 encoded)
# subscriptionID: "azure-subscription-id" # Azure subscription id (base64 encoded)
# tenantID: "azure-tenant-id" # Azure tenant id (base64 encoded)
type: Opaque
2 changes: 2 additions & 0 deletions kubernetes/Secrets/gcp-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ metadata:
data:
userData: "encoded-cloud-config" # GCP cloud config file (base64 encoded)
serviceAccountJSON: "{...}" # GCP service account json object (base64 encoded)
### Alternative data keys are:
# serviceaccount.json: "{...}" # GCP service account json object (base64 encoded)
type: Opaque
7 changes: 7 additions & 0 deletions pkg/apis/machine/v1alpha1/alicoud_machineclass_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ const (
AlicloudAccessKeyID string = "alicloudAccessKeyID"
// AlicloudAccessKeySecret is a constant for a key name that is part of the Alibaba cloud credentials.
AlicloudAccessKeySecret string = "alicloudAccessKeySecret"

// AlicloudAlternativeAccessKeyID is a constant for a key name of a secret containing the Alibaba cloud
// credentials (access key id).
AlicloudAlternativeAccessKeyID = "accessKeyID"
// AlicloudAlternativeAccessKeySecret is a constant for a key name of a secret containing the Alibaba cloud
// credentials (access key secret).
AlicloudAlternativeAccessKeySecret = "accessKeySecret"
)

// +genclient
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/machine/v1alpha1/aws_machineclass_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ const (
AWSAccessKeyID string = "providerAccessKeyId"
// AWSSecretAccessKey is a constant for a key name that is part of the AWS cloud credentials.
AWSSecretAccessKey string = "providerSecretAccessKey"

// AWSAlternativeAccessKeyID is a constant for a key name of a secret containing the AWS credentials (access key
// id).
AWSAlternativeAccessKeyID = "accessKeyID"
// AWSAlternativeAccessKeySecret is a constant for a key name of a secret containing the AWS credentials (access key
// secret).
AWSAlternativeSecretAccessKey = "secretAccessKey"
)

// +genclient
Expand Down
11 changes: 11 additions & 0 deletions pkg/apis/machine/v1alpha1/azure_machineclass_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ const (
AzureSubscriptionID string = "azureSubscriptionId"
// AzureTenantID is a constant for a key name that is part of the Azure cloud credentials.
AzureTenantID string = "azureTenantId"

// AzureAlternativeClientID is a constant for a key name of a secret containing the Azure credentials (client id).
AzureAlternativeClientID = "clientID"
// AzureAlternativeClientSecret is a constant for a key name of a secret containing the Azure credentials (client
// secret).
AzureAlternativeClientSecret = "clientSecret"
// AzureAlternativeSubscriptionID is a constant for a key name of a secret containing the Azure credentials
// (subscription id).
AzureAlternativeSubscriptionID = "subscriptionID"
// AzureAlternativeTenantID is a constant for a key name of a secret containing the Azure credentials (tenant id).
AzureAlternativeTenantID = "tenantID"
)

// +genclient
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/machine/v1alpha1/gcp_machineclass_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import (
const (
// GCPServiceAccountJSON is a constant for a key name that is part of the GCP cloud credentials.
GCPServiceAccountJSON string = "serviceAccountJSON"

// GCPAlternativeServiceAccountJSON is a constant for a key name of a secret containing the GCP credentials (service
// account json).
GCPAlternativeServiceAccountJSON = "serviceaccount.json"
)

// +genclient
Expand Down
14 changes: 14 additions & 0 deletions pkg/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ limitations under the License.
package driver

import (
"strings"

"github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"

corev1 "k8s.io/api/core/v1"
)

Expand Down Expand Up @@ -111,3 +114,14 @@ func NewDriver(machineID string, secretData map[string][]byte, classKind string,
},
)
}

// ExtractCredentialsFromData extracts and trims a value from the given data map. The first key that exists is being
// returned, otherwise, the next key is tried, etc. If no key exists then an empty string is returned.
func ExtractCredentialsFromData(data map[string][]byte, keys ...string) string {
for _, key := range keys {
if val, ok := data[key]; ok {
return strings.TrimSpace(string(val))
}
}
return ""
}
4 changes: 2 additions & 2 deletions pkg/driver/driver_alicloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ func (c *AlicloudDriver) decodeMachineID(id string) string {
}

func (c *AlicloudDriver) getEcsClient() (*ecs.Client, error) {
accessKeyID := strings.TrimSpace(string(c.CredentialsData[v1alpha1.AlicloudAccessKeyID]))
accessKeySecret := strings.TrimSpace(string(c.CredentialsData[v1alpha1.AlicloudAccessKeySecret]))
accessKeyID := ExtractCredentialsFromData(c.CredentialsData, v1alpha1.AlicloudAccessKeyID, v1alpha1.AlicloudAlternativeAccessKeyID)
accessKeySecret := ExtractCredentialsFromData(c.CredentialsData, v1alpha1.AlicloudAccessKeySecret, v1alpha1.AlicloudAlternativeAccessKeySecret)
region := c.AlicloudMachineClass.Spec.Region

var ecsClient *ecs.Client
Expand Down
4 changes: 2 additions & 2 deletions pkg/driver/driver_aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ func (d *AWSDriver) createSVC() (*ec2.EC2, error) {
Region: aws.String(d.AWSMachineClass.Spec.Region),
}

accessKeyID = strings.TrimSpace(string(d.CredentialsData[v1alpha1.AWSAccessKeyID]))
secretAccessKey = strings.TrimSpace(string(d.CredentialsData[v1alpha1.AWSSecretAccessKey]))
accessKeyID = ExtractCredentialsFromData(d.CredentialsData, v1alpha1.AWSAccessKeyID, v1alpha1.AWSAlternativeAccessKeyID)
secretAccessKey = ExtractCredentialsFromData(d.CredentialsData, v1alpha1.AWSSecretAccessKey, v1alpha1.AWSAlternativeSecretAccessKey)
)

if accessKeyID != "" && secretAccessKey != "" {
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/driver_aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var _ = Describe("Driver AWS", func() {
It("should convert multiples tags successfully", func() {
awsDriver := &AWSDriver{
AWSMachineClass: &v1alpha1.AWSMachineClass{},
CloudConfig: &corev1.Secret{},
CredentialsData: map[string][]byte{},
UserData: "dXNlciBkYXRhCg==",
MachineID: "ami-99fn8a892f94e765a",
MachineName: "machine-name",
Expand Down
8 changes: 4 additions & 4 deletions pkg/driver/driver_azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -395,10 +395,10 @@ func (d *AzureDriver) SetUserData(userData string) {

func (d *AzureDriver) setup() (*azureDriverClients, error) {
var (
subscriptionID = strings.TrimSpace(string(d.CredentialsData[v1alpha1.AzureSubscriptionID]))
tenantID = strings.TrimSpace(string(d.CredentialsData[v1alpha1.AzureTenantID]))
clientID = strings.TrimSpace(string(d.CredentialsData[v1alpha1.AzureClientID]))
clientSecret = strings.TrimSpace(string(d.CredentialsData[v1alpha1.AzureClientSecret]))
subscriptionID = ExtractCredentialsFromData(d.CredentialsData, v1alpha1.AzureSubscriptionID, v1alpha1.AzureAlternativeSubscriptionID)
tenantID = ExtractCredentialsFromData(d.CredentialsData, v1alpha1.AzureTenantID, v1alpha1.AzureAlternativeTenantID)
clientID = ExtractCredentialsFromData(d.CredentialsData, v1alpha1.AzureClientID, v1alpha1.AzureAlternativeClientID)
clientSecret = ExtractCredentialsFromData(d.CredentialsData, v1alpha1.AzureClientSecret, v1alpha1.AzureAlternativeClientSecret)
env = azure.PublicCloud
)
return newClients(subscriptionID, tenantID, clientID, clientSecret, env)
Expand Down
20 changes: 12 additions & 8 deletions pkg/driver/driver_gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ import (
"strings"
"time"

v1alpha1 "github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
"github.com/gardener/machine-controller-manager/pkg/metrics"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
compute "google.golang.org/api/compute/v1"
"google.golang.org/api/compute/v1"
"google.golang.org/api/googleapi"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/klog"

"github.com/gardener/machine-controller-manager/pkg/apis/machine/v1alpha1"
"github.com/gardener/machine-controller-manager/pkg/metrics"
)

const (
Expand All @@ -58,7 +59,7 @@ func (d *GCPDriver) Create() (string, string, error) {
return "Error", "Error", err
}

project, err := extractProject(d.CredentialsData[v1alpha1.GCPServiceAccountJSON])
project, err := extractProject(d.CredentialsData)
if err != nil {
return "Error", "Error", err
}
Expand Down Expand Up @@ -255,7 +256,7 @@ func (d *GCPDriver) GetVMs(machineID string) (VMs, error) {
return listOfVMs, err
}

project, err := extractProject(d.CredentialsData[v1alpha1.GCPServiceAccountJSON])
project, err := extractProject(d.CredentialsData)
if err != nil {
klog.Error(err)
return listOfVMs, err
Expand Down Expand Up @@ -302,8 +303,9 @@ func (d *GCPDriver) GetVMs(machineID string) (VMs, error) {

func (d *GCPDriver) createComputeService() (context.Context, *compute.Service, error) {
ctx := context.Background()
serviceAccountJSON := ExtractCredentialsFromData(d.CredentialsData, v1alpha1.GCPServiceAccountJSON, v1alpha1.GCPAlternativeServiceAccountJSON)

jwt, err := google.JWTConfigFromJSON(d.CredentialsData[v1alpha1.GCPServiceAccountJSON], compute.CloudPlatformScope)
jwt, err := google.JWTConfigFromJSON([]byte(serviceAccountJSON), compute.CloudPlatformScope)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -356,11 +358,13 @@ func (d *GCPDriver) decodeMachineID(id string) (string, string, string, error) {
return gce[0], gce[1], gce[2], nil
}

func extractProject(serviceaccount []byte) (string, error) {
func extractProject(credentialsData map[string][]byte) (string, error) {
serviceAccountJSON := ExtractCredentialsFromData(credentialsData, v1alpha1.GCPServiceAccountJSON, v1alpha1.GCPAlternativeServiceAccountJSON)

var j struct {
Project string `json:"project_id"`
}
if err := json.Unmarshal(serviceaccount, &j); err != nil {
if err := json.Unmarshal([]byte(serviceAccountJSON), &j); err != nil {
return "Error", err
}
return j.Project, nil
Expand Down
28 changes: 28 additions & 0 deletions pkg/driver/driver_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved.
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 driver

import (
"testing"
)
import . "github.com/onsi/ginkgo"
import . "github.com/onsi/gomega"

func TestDriverSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Driver Suite")
}
53 changes: 45 additions & 8 deletions pkg/driver/driver_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,49 @@
package driver
/*
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved.
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 driver_test

import (
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

. "github.com/gardener/machine-controller-manager/pkg/driver"
)
import . "github.com/onsi/ginkgo"
import . "github.com/onsi/gomega"

func TestDriverSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Driver Suite")
}
var _ = Describe("Driver", func() {
Describe("#ExtractCredentialsFromData", func() {
It("should return an empty string because data map is nil", func() {
Expect(ExtractCredentialsFromData(nil, "foo", "bar")).To(BeEmpty())
})

It("should return an empty string because data map is empty", func() {
Expect(ExtractCredentialsFromData(map[string][]byte{}, "foo", "bar")).To(BeEmpty())
})

It("should return an empty string because no keys provided", func() {
Expect(ExtractCredentialsFromData(map[string][]byte{"foo": []byte("bar")})).To(BeEmpty())
})

It("should return the value of the first matching key", func() {
Expect(ExtractCredentialsFromData(map[string][]byte{"foo": []byte(" bar")}, "foo", "bar")).To(Equal("bar"))
})

It("should return the value of the first matching key", func() {
Expect(ExtractCredentialsFromData(map[string][]byte{"foo": []byte(` bar
`)}, "bar", "foo")).To(Equal("bar"))
})
})
})

0 comments on commit 0e41070

Please sign in to comment.