From f4cb1be2a1e48f3a439b7744bca9f36ca0e41440 Mon Sep 17 00:00:00 2001 From: Nandor Kracser Date: Mon, 3 Jun 2019 16:10:31 +0200 Subject: [PATCH] move entrypoint querying into the webhook --- cmd/vault-env/entrypoint_cmd.go | 46 ---- cmd/vault-env/k8s.go | 131 ----------- cmd/vault-env/main.go | 11 +- cmd/vault-env/types.go | 26 --- cmd/vault-env/utils.go | 85 -------- cmd/vault-secrets-webhook/main.go | 46 ++-- .../registry/registry.go | 203 ++++++++++++++++++ cmd/vault-secrets-webhook/secret.go | 12 +- deploy/test-deployment.yaml | 2 + docs/mutating-webhook/README.md | 15 ++ go.mod | 2 +- 11 files changed, 258 insertions(+), 321 deletions(-) delete mode 100644 cmd/vault-env/entrypoint_cmd.go delete mode 100644 cmd/vault-env/k8s.go delete mode 100644 cmd/vault-env/types.go delete mode 100644 cmd/vault-env/utils.go create mode 100644 cmd/vault-secrets-webhook/registry/registry.go diff --git a/cmd/vault-env/entrypoint_cmd.go b/cmd/vault-env/entrypoint_cmd.go deleted file mode 100644 index fdbe558b0c..0000000000 --- a/cmd/vault-env/entrypoint_cmd.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright © 2019 Banzai Cloud -// -// 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 main - -import ( - "fmt" - "strings" - - "go.uber.org/zap" - - "github.com/banzaicloud/bank-vaults/pkg/vault" -) - -// GetEntrypointCmd returns entrypoint and command of container -func GetEntrypointCmd(vaultClient *vault.Client) ([]string, []string) { - podInfo := K8s{} - podInfo.Load() - - if podInfo.RegistryName != "" { - logger.Info("Trimmed registry name from image name", - zap.String("registry", podInfo.RegistryName), - zap.String("image", podInfo.Image), - ) - podInfo.Image = strings.TrimLeft(podInfo.Image, fmt.Sprintf("%s/", podInfo.RegistryName)) - } - - registryAddress := podInfo.RegistryAddress - if registryAddress == "" { - registryAddress = "https://registry-1.docker.io/" - } - logger.Warn("I'm using registry", zap.String("registry", registryAddress)) - - return GetImageBlob(registryAddress, podInfo.RegistryUsername, podInfo.RegistryPassword, podInfo.Image, podInfo.RegistryName) -} diff --git a/cmd/vault-env/k8s.go b/cmd/vault-env/k8s.go deleted file mode 100644 index 01d266974d..0000000000 --- a/cmd/vault-env/k8s.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright © 2019 Banzai Cloud -// -// 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 main - -import ( - "encoding/json" - "fmt" - "os" - "reflect" - - dockerTypes "github.com/docker/docker/api/types" - "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" -) - -// K8s structure keeps information retrieved from POD definition -type K8s struct { - clientset *kubernetes.Clientset - Namespace string - ImagePullSecrets string - RegistryAddress string - RegistryName string - RegistryUsername string - RegistryPassword string - Image string -} - -type dockerCreds struct { - Auths map[string]dockerTypes.AuthConfig `json:"auths"` -} - -func (k *K8s) newClientSet() error { - kubeConfig, err := rest.InClusterConfig() - if err != nil { - return err - } - - k.clientset, err = kubernetes.NewForConfig(kubeConfig) - if err != nil { - return err - } - return nil -} - -func (k *K8s) readDockerSecret(secretName string) (map[string][]byte, error) { - secret, err := k.clientset.CoreV1().Secrets(k.Namespace).Get(secretName, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return secret.Data, nil -} - -func (k *K8s) getNamespace() { - k.Namespace = os.Getenv("NAMESPACE") -} - -func (k *K8s) getPod(podName string) (*v1.Pod, error) { - pod, err := k.clientset.CoreV1().Pods(k.Namespace).Get(podName, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return pod, nil -} - -func (k *K8s) parseDockerConfig(dockerCreds dockerCreds) { - k.RegistryName = reflect.ValueOf(dockerCreds.Auths).MapKeys()[0].String() - k.RegistryAddress = fmt.Sprintf("https://%s", k.RegistryName) - - auths := dockerCreds.Auths - k.RegistryUsername = auths[k.RegistryName].Username - k.RegistryPassword = auths[k.RegistryName].Password -} - -// Load reads information from k8s and load them into the structure -func (k *K8s) Load() { - k.getNamespace() - k.newClientSet() - - podName := os.Getenv("MY_POD_NAME") - if podName == "" { - logger.Fatal("Cannot find MY_POD_NAME environment variable") - } - - pod, err := k.getPod(podName) - if err != nil { - logger.Fatal("Cannot get pod definition", zap.Error(err)) - } - - for _, container := range pod.Spec.Containers { - k.Image = container.Image - - containerName := os.Getenv("CONTAINER_NAME") - if containerName == container.Name && containerName != "" { - break - } - } - - if len(pod.Spec.ImagePullSecrets) >= 1 { - k.ImagePullSecrets = pod.Spec.ImagePullSecrets[0].Name - - if k.ImagePullSecrets != "" { - data, err := k.readDockerSecret(k.ImagePullSecrets) - if err != nil { - logger.Fatal("Cannot read imagePullSecrets", zap.Error(err)) - } - dockerConfig := data[v1.DockerConfigJsonKey] - //parse config - var dockerCreds dockerCreds - err = json.Unmarshal(dockerConfig, &dockerCreds) - if err != nil { - logger.Fatal("Cannot unmarshal docker configuration from imagePullSecrets", zap.Error(err)) - } - k.parseDockerConfig(dockerCreds) - } - } -} diff --git a/cmd/vault-env/main.go b/cmd/vault-env/main.go index 431a02bd54..6fda69499a 100644 --- a/cmd/vault-env/main.go +++ b/cmd/vault-env/main.go @@ -52,10 +52,6 @@ var sanitizeEnvmap = map[string]bool{ "VAULT_ROLE": true, "VAULT_PATH": true, "VAULT_IGNORE_MISSING_SECRETS": true, - "MY_POD_NAME": true, - "NAMESPACE": true, - "CONTAINER_NAME": true, - "REGISTRY_SKIP_VERIFY": true, } // Appends variable an entry (name=value) into the environ list. @@ -174,11 +170,8 @@ func main() { var entrypointCmd []string if len(os.Args) == 1 { - // reads entrypoint and cmd from image configuration - entrypoint, cmd := GetEntrypointCmd(client) - - logger.Info("Retrieved configuration", zap.Strings("entrypoint", entrypoint), zap.Strings("cmd", cmd)) - entrypointCmd = append(entrypoint, cmd...) + logger.Fatal("no command is given, vault-env can't determine the entrypoint (command), please specify it explicitly or let the webhook query it (see documentation)") + os.Exit(1) } else { entrypointCmd = os.Args[1:] } diff --git a/cmd/vault-env/types.go b/cmd/vault-env/types.go deleted file mode 100644 index 03c841c954..0000000000 --- a/cmd/vault-env/types.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright © 2019 Banzai Cloud -// -// 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 main - -// BlobResponse stores blob response -type BlobResponse struct { - Config Config `json:"config"` -} - -// Config stores Cmd and Entrypoint retrieved from blob response -type Config struct { - Cmd []string `json:"Cmd"` - Entrypoint []string `json:"Entrypoint"` -} diff --git a/cmd/vault-env/utils.go b/cmd/vault-env/utils.go deleted file mode 100644 index 09d67642dc..0000000000 --- a/cmd/vault-env/utils.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright © 2019 Banzai Cloud -// -// 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 main - -import ( - "encoding/json" - "io/ioutil" - "os" - "strings" - - "go.uber.org/zap" - - "github.com/heroku/docker-registry-client/registry" -) - -// GetImageBlob download image blob from registry -func GetImageBlob(url, username, password, image, registryName string) ([]string, []string) { - imageName, tag := ParseContainerImage(image) - - registrySkipVerify := os.Getenv("REGISTRY_SKIP_VERIFY") - - var hub *registry.Registry - var err error - - if registrySkipVerify == "true" { - hub, err = registry.NewInsecure(url, username, password) - } else { - hub, err = registry.New(url, username, password) - } - if err != nil { - logger.Fatal("Cannot create client for registry", zap.Error(err)) - } - - manifest, err := hub.ManifestV2(imageName, tag) - if err != nil { - logger.Fatal("Cannot download manifest for image", zap.Error(err)) - } - - reader, err := hub.DownloadBlob(imageName, manifest.Config.Digest) - if reader != nil { - defer reader.Close() - } - if err != nil { - logger.Fatal("Cannot download blob", zap.Error(err)) - } - - b, err := ioutil.ReadAll(reader) - if err != nil { - logger.Fatal("Cannot read blob", zap.Error(err)) - } - - var msg BlobResponse - err = json.Unmarshal(b, &msg) - if err != nil { - logger.Fatal("Cannot unmarshal JSON", zap.Error(err)) - } - - return msg.Config.Entrypoint, msg.Config.Cmd -} - -// ParseContainerImage returns image and tag -func ParseContainerImage(image string) (string, string) { - split := strings.SplitN(image, ":", 2) - - if len(split) <= 1 { - logger.Fatal("Cannot find tag for image", zap.String("image", image)) - } - - imageName := split[0] - tag := split[1] - - return imageName, tag -} diff --git a/cmd/vault-secrets-webhook/main.go b/cmd/vault-secrets-webhook/main.go index 9e2c6cca6e..7818630a7a 100644 --- a/cmd/vault-secrets-webhook/main.go +++ b/cmd/vault-secrets-webhook/main.go @@ -22,8 +22,9 @@ import ( "strconv" "strings" + "github.com/banzaicloud/bank-vaults/cmd/vault-secrets-webhook/registry" + log "github.com/sirupsen/logrus" whhttp "github.com/slok/kubewebhook/pkg/http" - "github.com/slok/kubewebhook/pkg/log" whcontext "github.com/slok/kubewebhook/pkg/webhook/context" "github.com/slok/kubewebhook/pkg/webhook/mutating" "github.com/spf13/viper" @@ -181,7 +182,7 @@ func getContainers(vaultConfig vaultConfig, containerEnvVars []corev1.EnvVar, co return containers } -func getVolumes(agentConfigMapName string, vaultConfig vaultConfig, logger log.Logger) []corev1.Volume { +func getVolumes(agentConfigMapName string, vaultConfig vaultConfig, logger *log.Logger) []corev1.Volume { logger.Debugf("Add generic volumes to podspec") volumes := []corev1.Volume{ @@ -477,7 +478,7 @@ func lookForValueFrom(env corev1.EnvVar, ns string) (*corev1.EnvVar, error) { return nil, nil } -func mutateContainers(containers []corev1.Container, vaultConfig vaultConfig, ns string) (bool, error) { +func mutateContainers(containers []corev1.Container, podSpec *corev1.PodSpec, vaultConfig vaultConfig, ns string) (bool, error) { mutated := false for i, container := range containers { @@ -514,6 +515,22 @@ func mutateContainers(containers []corev1.Container, vaultConfig vaultConfig, ns args := append(container.Command, container.Args...) + // the container has no explicitly specified command + if len(args) == 0 { + clientset, err := newClientSet() + if err != nil { + return false, err + } + + entrypoint, cmd, err := registry.GetEntrypointCmd(clientset, ns, &container, podSpec) + if err != nil { + return false, err + } + + args = append(args, entrypoint...) + args = append(args, cmd...) + } + container.Command = []string{"/vault/vault-env"} container.Args = args @@ -560,7 +577,7 @@ func mutateContainers(containers []corev1.Container, vaultConfig vaultConfig, ns return mutated, nil } -func addSecretsVolToContainers(containers []corev1.Container, logger log.Logger) { +func addSecretsVolToContainers(containers []corev1.Container, logger *log.Logger) { for i, container := range containers { @@ -578,6 +595,7 @@ func addSecretsVolToContainers(containers []corev1.Container, logger log.Logger) } +// TODO replace all the calls with a global clientset func newClientSet() (*kubernetes.Clientset, error) { kubeConfig, err := rest.InClusterConfig() if err != nil { @@ -593,8 +611,6 @@ func newClientSet() (*kubernetes.Clientset, error) { func mutatePodSpec(obj metav1.Object, podSpec *corev1.PodSpec, vaultConfig vaultConfig, ns string) error { - logger := &log.Std{Debug: viper.GetBool("debug")} - clientset, err := newClientSet() if err != nil { return err @@ -602,7 +618,7 @@ func mutatePodSpec(obj metav1.Object, podSpec *corev1.PodSpec, vaultConfig vault logger.Debugf("Successfully connected to the API") - initContainersMutated, err := mutateContainers(podSpec.InitContainers, vaultConfig, ns) + initContainersMutated, err := mutateContainers(podSpec.InitContainers, podSpec, vaultConfig, ns) if err != nil { return err } @@ -613,7 +629,7 @@ func mutatePodSpec(obj metav1.Object, podSpec *corev1.PodSpec, vaultConfig vault logger.Debugf("No pod init containers were mutated") } - containersMutated, err := mutateContainers(podSpec.Containers, vaultConfig, ns) + containersMutated, err := mutateContainers(podSpec.Containers, podSpec, vaultConfig, ns) if err != nil { return err } @@ -710,11 +726,11 @@ func mutatePodSpec(obj metav1.Object, podSpec *corev1.PodSpec, vaultConfig vault return nil } -func initConfig() { +func init() { viper.SetDefault("vault_image", "vault:latest") viper.SetDefault("vault_env_image", "banzaicloud/vault-env:latest") viper.SetDefault("vault_ct_image", "hashicorp/consul-template:0.19.6-dev-alpine") - viper.SetDefault("vault_addr", "https://127.0.0.1:8200") + viper.SetDefault("vault_addr", "https://vault:8200") viper.SetDefault("vault_skip_verify", "false") viper.SetDefault("vault_tls_secret", "") viper.SetDefault("vault_agent", "true") @@ -722,9 +738,11 @@ func initConfig() { viper.SetDefault("psp_allow_privilege_escalation", "false") viper.SetDefault("vault_ignore_missing_secrets", "false") viper.AutomaticEnv() + + logger = log.New() } -func handlerFor(config mutating.WebhookConfig, mutator mutating.MutatorFunc, logger log.Logger) http.Handler { +func handlerFor(config mutating.WebhookConfig, mutator mutating.MutatorFunc, logger *log.Logger) http.Handler { webhook, err := mutating.NewWebhook(config, mutator, nil, nil, logger) if err != nil { fmt.Fprintf(os.Stderr, "error creating webhook: %s", err) @@ -740,11 +758,9 @@ func handlerFor(config mutating.WebhookConfig, mutator mutating.MutatorFunc, log return handler } -func main() { - - initConfig() +var logger *log.Logger - logger := &log.Std{Debug: viper.GetBool("debug")} +func main() { mutator := mutating.MutatorFunc(vaultSecretsMutator) diff --git a/cmd/vault-secrets-webhook/registry/registry.go b/cmd/vault-secrets-webhook/registry/registry.go new file mode 100644 index 0000000000..90e119ef4a --- /dev/null +++ b/cmd/vault-secrets-webhook/registry/registry.go @@ -0,0 +1,203 @@ +// Copyright © 2019 Banzai Cloud +// +// 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 registry + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "reflect" + "strings" + + dockerTypes "github.com/docker/docker/api/types" + "github.com/heroku/docker-registry-client/registry" + imagev1 "github.com/opencontainers/image-spec/specs-go/v1" + log "github.com/sirupsen/logrus" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +var logger log.FieldLogger + +func init() { + logger = log.New() +} + +type DockerCreds struct { + Auths map[string]dockerTypes.AuthConfig `json:"auths"` +} + +// GetImageBlob download image blob from registry +func GetImageBlob(url, username, password, image string) ([]string, []string, error) { + imageName, tag, err := ParseContainerImage(image) + if err != nil { + return nil, nil, err + } + + registrySkipVerify := os.Getenv("REGISTRY_SKIP_VERIFY") + + var hub *registry.Registry + + if registrySkipVerify == "true" { + hub, err = registry.NewInsecure(url, username, password) + } else { + hub, err = registry.New(url, username, password) + } + if err != nil { + return nil, nil, fmt.Errorf("cannot create client for registry: %s", err.Error()) + } + + manifest, err := hub.ManifestV2(imageName, tag) + if err != nil { + return nil, nil, fmt.Errorf("cannot download manifest for image: %s", err.Error()) + } + + reader, err := hub.DownloadBlob(imageName, manifest.Config.Digest) + if reader != nil { + defer reader.Close() + } + if err != nil { + return nil, nil, fmt.Errorf("cannot download blob: %s", err.Error()) + } + + b, err := ioutil.ReadAll(reader) + if err != nil { + return nil, nil, fmt.Errorf("cannot read blob: %s", err.Error()) + } + + logger.Info("downloaded blob len: ", len(b)) + + var imageMetadata imagev1.Image + err = json.Unmarshal(b, &imageMetadata) + if err != nil { + return nil, nil, fmt.Errorf("cannot unmarshal BlobResponse JSON: %s", err.Error()) + } + + return imageMetadata.Config.Entrypoint, imageMetadata.Config.Cmd, nil +} + +// ParseContainerImage returns image and tag +func ParseContainerImage(image string) (string, string, error) { + split := strings.SplitN(image, ":", 2) + + if len(split) <= 1 { + return "", "", fmt.Errorf("Cannot find tag for image %s", image) + } + + imageName := split[0] + tag := split[1] + + return imageName, tag, nil +} + +func isDockerHub(registryAddress string) bool { + return strings.HasPrefix(registryAddress, "https://registry-1.docker.io") || strings.HasPrefix(registryAddress, "https://index.docker.io") +} + +// GetEntrypointCmd returns entrypoint and command of container +func GetEntrypointCmd(clientset *kubernetes.Clientset, namespace string, container *corev1.Container, podSpec *corev1.PodSpec) ([]string, []string, error) { + podInfo := K8s{Namespace: namespace, clientset: clientset} + + err := podInfo.Load(container, podSpec) + if err != nil { + return nil, nil, err + } + + if podInfo.RegistryName != "" { + logger.Info( + "Trimmed registry name from image name", + "registry", podInfo.RegistryName, + "image", podInfo.Image, + ) + podInfo.Image = strings.TrimLeft(podInfo.Image, fmt.Sprintf("%s/", podInfo.RegistryName)) + } + + registryAddress := podInfo.RegistryAddress + if registryAddress == "" { + registryAddress = "https://registry-1.docker.io/" + } + + // this is a library image on DockerHub, add the `libarary/` prefix + if isDockerHub(registryAddress) && strings.Count(podInfo.Image, "/") == 0 { + podInfo.Image = "library/" + podInfo.Image + } + + logger.Infoln("I'm using registry", registryAddress) + + return GetImageBlob(registryAddress, podInfo.RegistryUsername, podInfo.RegistryPassword, podInfo.Image) +} + +// K8s structure keeps information retrieved from POD definition +type K8s struct { + clientset *kubernetes.Clientset + Namespace string + ImagePullSecrets string + RegistryAddress string + RegistryName string + RegistryUsername string + RegistryPassword string + Image string +} + +func (k *K8s) readDockerSecret(namespace, secretName string) (map[string][]byte, error) { + secret, err := k.clientset.CoreV1().Secrets(namespace).Get(secretName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return secret.Data, nil +} + +func (k *K8s) parseDockerConfig(dockerCreds DockerCreds) { + k.RegistryName = reflect.ValueOf(dockerCreds.Auths).MapKeys()[0].String() + if !strings.HasPrefix(k.RegistryName, "https://") { + k.RegistryAddress = fmt.Sprintf("https://%s", k.RegistryName) + } else { + k.RegistryAddress = k.RegistryName + } + + auths := dockerCreds.Auths + k.RegistryUsername = auths[k.RegistryName].Username + k.RegistryPassword = auths[k.RegistryName].Password +} + +// Load reads information from k8s and load them into the structure +func (k *K8s) Load(container *corev1.Container, podSpec *corev1.PodSpec) error { + + k.Image = container.Image + + if len(podSpec.ImagePullSecrets) >= 1 { + k.ImagePullSecrets = podSpec.ImagePullSecrets[0].Name + + if k.ImagePullSecrets != "" { + data, err := k.readDockerSecret(k.Namespace, k.ImagePullSecrets) + if err != nil { + return fmt.Errorf("cannot read imagePullSecrets: %s", err.Error()) + } + + dockerConfig := data[corev1.DockerConfigJsonKey] + + var dockerCreds DockerCreds + err = json.Unmarshal(dockerConfig, &dockerCreds) + if err != nil { + return fmt.Errorf("cannot unmarshal docker configuration from imagePullSecrets: %s", err.Error()) + } + k.parseDockerConfig(dockerCreds) + } + } + + return nil +} diff --git a/cmd/vault-secrets-webhook/secret.go b/cmd/vault-secrets-webhook/secret.go index 8a725414cd..a2a0894b9c 100644 --- a/cmd/vault-secrets-webhook/secret.go +++ b/cmd/vault-secrets-webhook/secret.go @@ -22,6 +22,7 @@ import ( "os" "strings" + "github.com/banzaicloud/bank-vaults/cmd/vault-secrets-webhook/registry" "github.com/banzaicloud/bank-vaults/pkg/vault" dockerTypes "github.com/docker/docker/api/types" vaultapi "github.com/hashicorp/vault/api" @@ -32,12 +33,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -type dockerCreds struct { - Auths map[string]dockerTypes.AuthConfig `json:"auths"` -} - func mutateSecret(obj metav1.Object, secret *corev1.Secret, vaultConfig vaultConfig, ns string) error { - logger := &log.Std{Debug: viper.GetBool("debug")} logger.Debugf("SecretData: %s", secret.Data) os.Setenv("VAULT_ADDR", vaultConfig.addr) @@ -45,7 +41,7 @@ func mutateSecret(obj metav1.Object, secret *corev1.Secret, vaultConfig vaultCon for key, value := range secret.Data { if key == corev1.DockerConfigJsonKey { - var dc dockerCreds + var dc registry.DockerCreds err := json.Unmarshal(value, &dc) if err != nil { return fmt.Errorf("unmarshal dockerconfig json failed: %v", err) @@ -71,10 +67,10 @@ func mutateSecret(obj metav1.Object, secret *corev1.Secret, vaultConfig vaultCon return nil } -func mutateDockerCreds(secret *corev1.Secret, dc *dockerCreds, vaultConfig vaultConfig) error { +func mutateDockerCreds(secret *corev1.Secret, dc *registry.DockerCreds, vaultConfig vaultConfig) error { logger := &log.Std{Debug: viper.GetBool("debug")} - assembled := dockerCreds{Auths: map[string]dockerTypes.AuthConfig{}} + assembled := registry.DockerCreds{Auths: map[string]dockerTypes.AuthConfig{}} for key, creds := range dc.Auths { authBytes, err := base64.StdEncoding.DecodeString(creds.Auth) diff --git a/deploy/test-deployment.yaml b/deploy/test-deployment.yaml index fb8c69527d..cc02b4f398 100644 --- a/deploy/test-deployment.yaml +++ b/deploy/test-deployment.yaml @@ -32,3 +32,5 @@ spec: env: - name: AWS_SECRET_ACCESS_KEY value: vault:secret/data/accounts/aws#AWS_SECRET_ACCESS_KEY + # imagePullSecrets: + # - sample-secret diff --git a/docs/mutating-webhook/README.md b/docs/mutating-webhook/README.md index b88c79ab55..a7c67cc15d 100644 --- a/docs/mutating-webhook/README.md +++ b/docs/mutating-webhook/README.md @@ -144,3 +144,18 @@ kubectl annotate secret dockerhub vault.security.banzaicloud.io/vault-role="defa kubectl annotate secret dockerhub vault.security.banzaicloud.io/vault-skip-verify="true" kubectl annotate secret dockerhub vault.security.banzaicloud.io/vault-path="kubernetes" ``` + + +## Using charts without explicit container.command and container.args: + +```bash +helm upgrade --install mysql stable/mysql --set mysqlRootPassword=vault:secret/data/mysql#MYSQL_ROOT_PASSWORD --set-string "podAnnotations.vault\.security\.banzaicloud\.io/vault-skip-verify=true" +``` + +When using a private image repository: + +```bash +kubectl create secret docker-registry dockerhub --docker-username=${DOCKER_USERNAME} --docker-password=$DOCKER_PASSWORD --docker-server=https://index.docker.io + +helm upgrade --install mysql stable/mysql --set mysqlRootPassword=vault:secret/data/mysql#MYSQL_ROOT_PASSWORD --set "imagePullSecrets[0].name=dockerhub" --set-string "podAnnotations.vault\.security\.banzaicloud\.io/vault-skip-verify=true" --set image="private-repo/mysql" +``` diff --git a/go.mod b/go.mod index 747d32d2bf..b2bc4b134c 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,7 @@ require ( github.com/onsi/ginkgo v1.7.0 // indirect github.com/onsi/gomega v1.4.3 // indirect github.com/opencontainers/go-digest v1.0.0-rc1 // indirect - github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/image-spec v1.0.1 github.com/operator-framework/operator-sdk v0.7.0 github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect