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

improve kubeconfig/gcp handling of credentials in e2e tests #1404

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/cloud-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ tags:
### machine.spec.providerConfig.cloudProviderSpec

```yaml
serviceAccount: "<< GOOGLE_SERVICE_ACCOUNT >>"
# The service account needs to be base64-encoded.
serviceAccount: "<< GOOGLE_SERVICE_ACCOUNT_BASE64 >>"
# See https://cloud.google.com/compute/docs/regions-zones/
zone: "europe-west3-a"
# See https://cloud.google.com/compute/docs/machine-types
Expand Down Expand Up @@ -302,8 +303,8 @@ tags:

### machine.spec.providerConfig.cloudProviderSpec
```yaml
# kubeconfig to access KubeVirt cluster
kubeconfig: '<< KUBECONFIG >>'
# base64-encoded kubeconfig to access KubeVirt cluster
kubeconfig: '<< KUBECONFIG_BASE64 >>'
# KubeVirt namespace
namespace: kube-system
# kubernetes storage class
Expand Down
9 changes: 7 additions & 2 deletions examples/gce-machinedeployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ metadata:
name: machine-controller-gce
namespace: kube-system
type: Opaque
stringData:
serviceAccount: "<< GOOGLE_SERVICE_ACCOUNT >>"
data:
# The base64 encoding here is only to satisfy Kubernetes'
# Secret storage and to prevent multiline string replacement
# issues if we used stringData here (because the GCP SA is
# a multiline JSON string).
serviceAccount: "<< GOOGLE_SERVICE_ACCOUNT_BASE64 >>"

---
apiVersion: "cluster.k8s.io/v1alpha1"
kind: MachineDeployment
Expand Down
6 changes: 3 additions & 3 deletions examples/kubevirt-machinedeployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ spec:
cloudProviderSpec:
auth:
kubeconfig:
# Can also be set via the env var 'KUBEVIRT_KUBECONFIG' on the machine-controller
# If specified directly, this value should be a base64 encoded kubeconfig in either yaml or json format.
value: "<< KUBECONFIG >>"
# Can also be set via the env var 'KUBEVIRT_KUBECONFIG' on the machine-controller.
# If instead specified directly, this value should be a base64 encoded kubeconfig.
value: "<< KUBECONFIG_BASE64 >>"
virtualMachine:
template:
cpus: "1"
Expand Down
16 changes: 11 additions & 5 deletions pkg/cloudprovider/provider/gce/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,17 +226,23 @@ func newConfig(resolver *providerconfig.ConfigVarResolver, spec v1alpha1.Provide
// postprocessServiceAccount processes the service account and creates a JWT configuration
// out of it.
func (cfg *config) postprocessServiceAccount() error {
sa, err := base64.StdEncoding.DecodeString(cfg.serviceAccount)
if err != nil {
return fmt.Errorf("failed to decode base64 service account: %w", err)
sa := cfg.serviceAccount

// safely decode the service account, in case we did not read the value
// from a "known-safe" location (like the MachineDeployment), but from
// an environment variable.
decoded, err := base64.StdEncoding.DecodeString(cfg.serviceAccount)
if err == nil {
sa = string(decoded)
}

sam := map[string]string{}
err = json.Unmarshal(sa, &sam)
err = json.Unmarshal([]byte(sa), &sam)
if err != nil {
return fmt.Errorf("failed unmarshalling service account: %w", err)
}
cfg.projectID = sam["project_id"]
cfg.jwtConfig, err = google.JWTConfigFromJSON(sa, compute.ComputeScope)
cfg.jwtConfig, err = google.JWTConfigFromJSON([]byte(sa), compute.ComputeScope)
if err != nil {
return fmt.Errorf("failed preparing JWT: %w", err)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/cloudprovider/provider/gce/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
// CloudProviderSpec contains the specification of the cloud provider taken
// from the provider configuration.
type CloudProviderSpec struct {
// ServiceAccount must be base64-encoded.
ServiceAccount providerconfigtypes.ConfigVarString `json:"serviceAccount,omitempty"`
Zone providerconfigtypes.ConfigVarString `json:"zone"`
MachineType providerconfigtypes.ConfigVarString `json:"machineType"`
Expand Down
17 changes: 15 additions & 2 deletions test/e2e/provisioning/all_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package provisioning

import (
"context"
"encoding/base64"
"flag"
"fmt"
"os"
Expand Down Expand Up @@ -293,12 +294,23 @@ func TestKubevirtProvisioningE2E(t *testing.T) {
selector := OsSelector("ubuntu", "centos", "flatcar", "rockylinux")

params := []string{
fmt.Sprintf("<< KUBECONFIG >>=%s", kubevirtKubeconfig),
fmt.Sprintf("<< KUBECONFIG_BASE64 >>=%s", safeBase64Encoding(kubevirtKubeconfig)),
}

runScenarios(t, selector, params, kubevirtManifest, fmt.Sprintf("kubevirt-%s", *testRunIdentifier))
}

// safeBase64Encoding takes a value and encodes it with base64
// if it is not already encoded.
func safeBase64Encoding(value string) string {
// If there was no error, the original value was already encoded.
if _, err := base64.StdEncoding.DecodeString(value); err == nil {
return value
}

return base64.StdEncoding.EncodeToString([]byte(value))
}

func TestOpenstackProvisioningE2E(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -708,8 +720,9 @@ func TestGCEProvisioningE2E(t *testing.T) {
// Act. GCE does not support CentOS.
selector := OsSelector("ubuntu")
params := []string{
fmt.Sprintf("<< GOOGLE_SERVICE_ACCOUNT >>=%s", googleServiceAccount),
fmt.Sprintf("<< GOOGLE_SERVICE_ACCOUNT_BASE64 >>=%s", safeBase64Encoding(googleServiceAccount)),
}

runScenarios(t, selector, params, GCEManifest, fmt.Sprintf("gce-%s", *testRunIdentifier))
}

Expand Down
5 changes: 3 additions & 2 deletions test/e2e/provisioning/testdata/machinedeployment-gce.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ spec:
- "<< YOUR_PUBLIC_KEY >>"
cloudProvider: "gce"
cloudProviderSpec:
# If empty, can be set via GOOGLE_SERVICE_ACCOUNT env var
serviceAccount: "<< GOOGLE_SERVICE_ACCOUNT >>"
# If empty, can be set via GOOGLE_SERVICE_ACCOUNT env var. The environment variable
# should be plaintext. The value in the cloudProviderSpec however must be base64-encoded.
serviceAccount: "<< GOOGLE_SERVICE_ACCOUNT_BASE64 >>"
# See https://cloud.google.com/compute/docs/regions-zones/
zone: "europe-west3-a"
# See https://cloud.google.com/compute/docs/machine-types
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ spec:
cloudProviderSpec:
auth:
kubeconfig:
value: '<< KUBECONFIG >>'
value: '<< KUBECONFIG_BASE64 >>'
virtualMachine:
template:
cpus: "1"
Expand Down