diff --git a/CHANGELOG.md b/CHANGELOG.md index 554e311..ce215fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog for Vault Sidecar Injector +## Release v7.1.1 - 2021-04-02 + +**Fixed** + +- [VSI #45](https://github.com/Talend/vault-sidecar-injector/pull/45) - Do not inject sidecars if only job and secrets modes are enabled and secrets type is "static" + ## Release v7.1.0 - 2021-02-09 A new `sidecar.vault.talend.org/vault-image` annotation has been added to override the default injected image. Refer to the [samples](samples) for a [working example](samples/app-dep-10-secrets_custom_image_notify.yaml). diff --git a/VERSION_CHART b/VERSION_CHART index ef8d756..d87edbf 100644 --- a/VERSION_CHART +++ b/VERSION_CHART @@ -1 +1 @@ -4.2.0 \ No newline at end of file +4.2.1 \ No newline at end of file diff --git a/VERSION_RELEASE b/VERSION_RELEASE index 3769235..ef09838 100644 --- a/VERSION_RELEASE +++ b/VERSION_RELEASE @@ -1 +1 @@ -7.1.0 \ No newline at end of file +7.1.1 \ No newline at end of file diff --git a/VERSION_VSI b/VERSION_VSI index 3769235..ef09838 100644 --- a/VERSION_VSI +++ b/VERSION_VSI @@ -1 +1 @@ -7.1.0 \ No newline at end of file +7.1.1 \ No newline at end of file diff --git a/doc/Usage.md b/doc/Usage.md index aea99fb..fb17aff 100644 --- a/doc/Usage.md +++ b/doc/Usage.md @@ -113,7 +113,7 @@ Depending on the modes you decide to enable and whether you opt for static or dy XX - XX¹X (secrets)X (job) + XX¹X (secrets) XX @@ -141,6 +141,6 @@ Depending on the modes you decide to enable and whether you opt for static or dy -> **[1]** *on job mode:* if you only set mode annotation's value to "job", `secrets` mode will be enabled automatically and configured to handle dynamic secrets (unless you set `sidecar.vault.talend.org/secrets-type` to "static" but note that in this situation, there is no need, although we do not prevent it, to enable job mode as no Vault Agent will be injected as sidecar). +> **[1]** *on job mode:* if you only set mode annotation's value to "job", `secrets` mode will be enabled automatically and configured to handle dynamic secrets (unless you set `sidecar.vault.talend.org/secrets-type` to "static" but note that in this situation, there is no need, although we do not prevent it, to enable job mode explicitly as no sidecar will be injected). -> **[2]** *on number of injected sidecars:* for Kubernetes **Deployment** workloads, **only one sidecar container** is added to your pod to handle dynamic secrets and/or proxy. For Kubernetes **Job** workloads, **two sidecars** are injected to achieve the same tasks. +> **[2]** *on number of injected sidecars:* for Kubernetes **Deployment** workloads, **only one sidecar container** is added to your pod to handle dynamic secrets and/or proxy. For Kubernetes **Job** workloads, **two sidecars** are injected to achieve the same tasks (or 0 in case you only enable job mode with static secrets). diff --git a/doc/announcements/Static-vs-Dynamic-Secrets.md b/doc/announcements/Static-vs-Dynamic-Secrets.md index edfe94e..f258ef5 100644 --- a/doc/announcements/Static-vs-Dynamic-Secrets.md +++ b/doc/announcements/Static-vs-Dynamic-Secrets.md @@ -6,7 +6,7 @@ Available with `Vault Sidecar Injector` version **`6.0.0`**, *static secrets* su A new annotation, `sidecar.vault.talend.org/secrets-type`, is supported to explicitly define what kind of secrets you intend to fetch, default being *dynamic secrets*. -When *static secrets* are set, `Vault Sidecar Injector` will only inject an init container in your workload's pod. Fetched secrets will be stored in a file in a shared memory volume, the same way it is already done for *dynamic secrets*. As a result, if you do not enable other modes (e.g. *proxy*, *job*) no sidecar will be added. It also means that you don't have to leverage hooks or wait for the injected Vault Agent to fetch your secrets: your workload can access the values right after its container is started. The drawback of course is that your secrets **will not be automatically refreshed upon changes**, opt for *dynamic secrets* if this behavior is required. +When *static secrets* are set, `Vault Sidecar Injector` will only inject an init container in your workload's pod. Fetched secrets will be stored in a file in a shared memory volume, the same way it is already done for *dynamic secrets*. As a result, if you do not enable other modes (e.g. *proxy*) no sidecar will be added (Note that enabling *job* mode with static secrets will not incur any sidecar injection either). It also means that you don't have to leverage hooks or wait for the injected Vault Agent to fetch your secrets: your workload can access the values right after its container is started. The drawback of course is that your secrets **will not be automatically refreshed upon changes**, opt for *dynamic secrets* if this behavior is required. If you enable several modes, you may end up with both init container and sidecar(s) in your workload. A comprehensive table is provided in the main documention in section [Modes and Injection Config Overview](../Usage.md#modes-and-injection-config-overview). diff --git a/pkg/mode/constants.go b/pkg/mode/constants.go new file mode 100644 index 0000000..8ad2dca --- /dev/null +++ b/pkg/mode/constants.go @@ -0,0 +1,22 @@ +// Copyright © 2019-2021 Talend - www.talend.com +// +// 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 mode + +const ( + //--- Vault Sidecar Injector supported modes + VaultInjectorModeSecrets = "secrets" // Enable fetching of secrets from Vault store + VaultInjectorModeProxy = "proxy" // Enable local Vault proxy + VaultInjectorModeJob = "job" // Enable handling of Kubernetes Job +) diff --git a/pkg/mode/job/constants.go b/pkg/mode/job/constants.go index ea65441..948c673 100644 --- a/pkg/mode/job/constants.go +++ b/pkg/mode/job/constants.go @@ -25,8 +25,3 @@ const ( jobContainerNameEnv = "VSI_JOB_CNT_NAME" // Env var for name of the app job's container jobWorkloadEnv = "VSI_JOB_WORKLOAD" // Env var set to "true" if submitted workload is a k8s job ) - -const ( - //--- Vault Sidecar Injector supported modes - VaultInjectorModeJob = "job" // Enable handling of Kubernetes Job -) diff --git a/pkg/mode/job/job-func-inject.go b/pkg/mode/job/job-func-inject.go index 45de503..381871e 100644 --- a/pkg/mode/job/job-func-inject.go +++ b/pkg/mode/job/job-func-inject.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package job import ( "errors" ctx "talend/vault-sidecar-injector/pkg/context" + m "talend/vault-sidecar-injector/pkg/mode" + "talend/vault-sidecar-injector/pkg/mode/secrets" corev1 "k8s.io/api/core/v1" "k8s.io/klog" @@ -25,13 +27,21 @@ import ( func jobModeInject(containerBasePath string, podContainers []corev1.Container, containerName string, env []corev1.EnvVar, context *ctx.InjectionContext) (bool, error) { if (containerBasePath == ctx.JsonPathContainers) && (len(podContainers) != 1) { err := errors.New("Submitted pod should contain only one container") - klog.Errorf("[%s] %s", VaultInjectorModeJob, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeJob, err.Error()) return false, err } + // If static secrets and job (+ secrets as it'll be enabled also) are the only enabled modes then do not inject job containers as sidecars (no need for job babysitter nor Vault Agent) + if (containerBasePath == ctx.JsonPathContainers) && + m.IsEnabledModes(context.ModesStatus, []string{m.VaultInjectorModeSecrets, m.VaultInjectorModeJob}) && + secrets.IsSecretsStatic(context) { + klog.Infof("[%s] Static secrets in use and only enabled modes are '%s' and '%s': skip injecting job container %s (path: %s)", m.VaultInjectorModeJob, m.VaultInjectorModeJob, m.VaultInjectorModeSecrets, containerName, containerBasePath) + return false, nil + } + for _, cntName := range jobContainerNames[containerBasePath] { if cntName == containerName { - klog.Infof("[%s] Injecting container %s (path: %s)", VaultInjectorModeJob, containerName, containerBasePath) + klog.Infof("[%s] Injecting container %s (path: %s)", m.VaultInjectorModeJob, containerName, containerBasePath) // Resolve job env vars for envIdx := range env { diff --git a/pkg/mode/job/job.go b/pkg/mode/job/job.go index ba60c36..5042700 100644 --- a/pkg/mode/job/job.go +++ b/pkg/mode/job/job.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ func init() { // Register mode m.RegisterMode( m.VaultInjectorModeInfo{ - Key: VaultInjectorModeJob, + Key: m.VaultInjectorModeJob, DefaultMode: false, EnableDefaultMode: true, // Default mode will also be enabled if job is **the only mode on** (as it does not make sense to have only this mode) InjectContainerFunc: jobModeInject, diff --git a/pkg/mode/mode.go b/pkg/mode/mode.go index e23051e..bf8d2ce 100644 --- a/pkg/mode/mode.go +++ b/pkg/mode/mode.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package mode import ( "os" + "github.com/stretchr/testify/assert" "k8s.io/klog" ) @@ -78,3 +79,21 @@ func GetModesStatus(requestedModes []string, modes map[string]bool) { modes[defaultModeKey] = true } } + +// Use assert.ElementsMatch for comparing slices, but with a bool result. +type dummyt struct{} + +func (t dummyt) Errorf(string, ...interface{}) {} + +func IsEnabledModes(modesStatus map[string]bool, modesToCheck []string) bool { + var enabledModes []string + + for mode, enabled := range modesStatus { + if enabled { + enabledModes = append(enabledModes, mode) + } + } + + // Allow to check for equality on slices without order. See https://stackoverflow.com/a/66062073 + return assert.ElementsMatch(dummyt{}, enabledModes, modesToCheck) +} diff --git a/pkg/mode/proxy/constants.go b/pkg/mode/proxy/constants.go index f30d6a2..0b53d25 100644 --- a/pkg/mode/proxy/constants.go +++ b/pkg/mode/proxy/constants.go @@ -35,8 +35,3 @@ const ( //--- Vault Agent env vars related to modes vaultProxyConfigPlaceholderEnv = "VSI_PROXY_CONFIG_PLACEHOLDER" ) - -const ( - //--- Vault Sidecar Injector supported modes - VaultInjectorModeProxy = "proxy" // Enable local Vault proxy -) diff --git a/pkg/mode/proxy/proxy-func-inject.go b/pkg/mode/proxy/proxy-func-inject.go index 57b42d2..c3a7b9c 100644 --- a/pkg/mode/proxy/proxy-func-inject.go +++ b/pkg/mode/proxy/proxy-func-inject.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package proxy import ( ctx "talend/vault-sidecar-injector/pkg/context" + m "talend/vault-sidecar-injector/pkg/mode" corev1 "k8s.io/api/core/v1" "k8s.io/klog" @@ -24,12 +25,12 @@ import ( func proxyModeInject(containerBasePath string, podContainers []corev1.Container, containerName string, env []corev1.EnvVar, context *ctx.InjectionContext) (bool, error) { for _, cntName := range proxyContainerNames[containerBasePath] { if cntName == containerName { - klog.Infof("[%s] Injecting container %s (path: %s)", VaultInjectorModeProxy, containerName, containerBasePath) + klog.Infof("[%s] Injecting container %s (path: %s)", m.VaultInjectorModeProxy, containerName, containerBasePath) // Resolve proxy env vars for envIdx := range env { if env[envIdx].Name == vaultProxyConfigPlaceholderEnv { - env[envIdx].Value = context.ModesConfig[VaultInjectorModeProxy].GetTemplate() + env[envIdx].Value = context.ModesConfig[m.VaultInjectorModeProxy].GetTemplate() } } diff --git a/pkg/mode/proxy/proxy.go b/pkg/mode/proxy/proxy.go index c045dec..41dd6d2 100644 --- a/pkg/mode/proxy/proxy.go +++ b/pkg/mode/proxy/proxy.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ func init() { // Register mode m.RegisterMode( m.VaultInjectorModeInfo{ - Key: VaultInjectorModeProxy, + Key: m.VaultInjectorModeProxy, DefaultMode: false, EnableDefaultMode: false, Annotations: []string{vaultInjectorAnnotationProxyPortKey}, diff --git a/pkg/mode/secrets/constants.go b/pkg/mode/secrets/constants.go index 08ca1dc..64853c5 100644 --- a/pkg/mode/secrets/constants.go +++ b/pkg/mode/secrets/constants.go @@ -57,11 +57,6 @@ const ( secretsTemplatesPlaceholderEnv = "VSI_SECRETS_TEMPLATES_PLACEHOLDER" ) -const ( - //--- Vault Sidecar Injector supported modes - VaultInjectorModeSecrets = "secrets" // Enable fetching of secrets from Vault store -) - const ( //--- Vault Sidecar Injector secrets type vaultInjectorSecretsTypeDynamic = "dynamic" diff --git a/pkg/mode/secrets/secrets-func-compute.go b/pkg/mode/secrets/secrets-func-compute.go index e85903c..7400da8 100644 --- a/pkg/mode/secrets/secrets-func-compute.go +++ b/pkg/mode/secrets/secrets-func-compute.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import ( "strings" cfg "talend/vault-sidecar-injector/pkg/config" ctx "talend/vault-sidecar-injector/pkg/context" + m "talend/vault-sidecar-injector/pkg/mode" "k8s.io/klog" ) @@ -49,7 +50,7 @@ func secretsModeCompute(config *cfg.VSIConfig, labels, annotations map[string]st if !secretsTypeSupported { err := fmt.Errorf("Submitted pod makes use of unsupported secrets type '%s'", secretsType) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } } @@ -67,7 +68,7 @@ func secretsModeCompute(config *cfg.VSIConfig, labels, annotations map[string]st if !secretsInjectionMethodSupported { err := fmt.Errorf("Submitted pod makes use of unsupported secrets injection method '%s'", secretsInjectionMethod) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } } @@ -75,14 +76,14 @@ func secretsModeCompute(config *cfg.VSIConfig, labels, annotations map[string]st // If dynamic secrets and injection method is "env": return error (unsupported) if secretsType == vaultInjectorSecretsTypeDynamic && secretsInjectionMethod == vaultInjectorSecretsInjectionMethodEnv { err := fmt.Errorf("Submitted pod uses unsupported combination of secrets injection method '%s' with dynamic secrets", vaultInjectorSecretsInjectionMethodEnv) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } // If authentication method is "approle" and static secrets: return error (unsupported because, as static secrets, approle needs initContainer) if secretsType == vaultInjectorSecretsTypeStatic && annotations[config.VaultInjectorAnnotationsFQ[ctx.VaultInjectorAnnotationAuthMethodKey]] == ctx.VaultAppRoleAuthMethod { err := fmt.Errorf("Submitted pod uses unsupported combination of Vault Auth Method '%s' with static secrets", ctx.VaultAppRoleAuthMethod) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } @@ -92,7 +93,7 @@ func secretsModeCompute(config *cfg.VSIConfig, labels, annotations map[string]st if applicationLabel == "" || applicationServiceLabel == "" { err := fmt.Errorf("Submitted pod must contain labels %s and %s", config.ApplicationLabelKey, config.ApplicationServiceLabelKey) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } @@ -107,7 +108,7 @@ func secretsModeCompute(config *cfg.VSIConfig, labels, annotations map[string]st // We must have same numbers of secrets path & secrets destinations if templateDestNum != secretsPathNum { err := errors.New("Submitted pod must contain same numbers of secrets path and secrets destinations") - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } @@ -120,7 +121,7 @@ func secretsModeCompute(config *cfg.VSIConfig, labels, annotations map[string]st // We must have same numbers of custom templates & secrets destinations ... if templateDestNum != secretsTemplateNum { err := errors.New("Submitted pod must contain same numbers of templates and secrets destinations") - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return nil, err } diff --git a/pkg/mode/secrets/secrets-func-inject.go b/pkg/mode/secrets/secrets-func-inject.go index 595702a..63e4fee 100644 --- a/pkg/mode/secrets/secrets-func-inject.go +++ b/pkg/mode/secrets/secrets-func-inject.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package secrets import ( ctx "talend/vault-sidecar-injector/pkg/context" + m "talend/vault-sidecar-injector/pkg/mode" corev1 "k8s.io/api/core/v1" "k8s.io/klog" @@ -25,20 +26,20 @@ func secretsModeInject(containerBasePath string, podContainers []corev1.Containe for _, cntName := range secretsContainerNames[containerBasePath] { if cntName == containerName { // Look type of secrets: inject init container only for static secrets - if (isSecretsStatic(context) && (containerBasePath == ctx.JsonPathInitContainers)) || - (!isSecretsStatic(context) && (containerBasePath == ctx.JsonPathContainers)) { + if (IsSecretsStatic(context) && (containerBasePath == ctx.JsonPathInitContainers)) || + (!IsSecretsStatic(context) && (containerBasePath == ctx.JsonPathContainers)) { - if (cntName == secretsEnvInitContainerName) && !isSecretsInjectionEnv(context) { + if (cntName == secretsEnvInitContainerName) && !IsSecretsInjectionEnv(context) { // Do not inject env init container if injection method is not 'env' return false, nil } - klog.Infof("[%s] Injecting container %s (path: %s)", VaultInjectorModeSecrets, containerName, containerBasePath) + klog.Infof("[%s] Injecting container %s (path: %s)", m.VaultInjectorModeSecrets, containerName, containerBasePath) // Resolve secrets env vars for envIdx := range env { if env[envIdx].Name == secretsTemplatesPlaceholderEnv { - env[envIdx].Value = context.ModesConfig[VaultInjectorModeSecrets].GetTemplate() + env[envIdx].Value = context.ModesConfig[m.VaultInjectorModeSecrets].GetTemplate() } } diff --git a/pkg/mode/secrets/secrets-func-patch.go b/pkg/mode/secrets/secrets-func-patch.go index ae90796..5d4c125 100644 --- a/pkg/mode/secrets/secrets-func-patch.go +++ b/pkg/mode/secrets/secrets-func-patch.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import ( "strings" cfg "talend/vault-sidecar-injector/pkg/config" ctx "talend/vault-sidecar-injector/pkg/context" - "talend/vault-sidecar-injector/pkg/mode/job" + m "talend/vault-sidecar-injector/pkg/mode" corev1 "k8s.io/api/core/v1" @@ -32,13 +32,13 @@ import ( func secretsModePatch(config *cfg.VSIConfig, podSpec corev1.PodSpec, annotations map[string]string, context *ctx.InjectionContext) (patch []ctx.PatchOperation, err error) { var patchHooks, patchCmd []ctx.PatchOperation - if !isSecretsStatic(context) { // Only for dynamic secrets + if !IsSecretsStatic(context) { // Only for dynamic secrets // Add lifecycle hooks to requesting pod's container(s) if needed if patchHooks, err = addLifecycleHooks(config, podSpec.Containers, annotations, context); err == nil { patch = append(patch, patchHooks...) } } else { - if isSecretsInjectionEnv(context) { // Look if injection method is set to 'env' + if IsSecretsInjectionEnv(context) { // Look if injection method is set to 'env' // Patch containers' commands to invoke 'vaultinjector-env' process first to add env vars from secrets if patchCmd, err = patchCommand(podSpec.Containers); err == nil { patch = append(patch, patchCmd...) @@ -70,7 +70,7 @@ func patchCommand(podContainers []corev1.Container) (patch []ctx.PatchOperation, }) } else { err = fmt.Errorf("No explicit command found for container %s", podCnt.Name) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return } } @@ -84,16 +84,16 @@ func addLifecycleHooks(config *cfg.VSIConfig, podContainers []corev1.Container, return case "y", "yes", "true", "on": // Check if job mode is enabled: this annotation should not be used then - if context.ModesStatus[job.VaultInjectorModeJob] { - err = fmt.Errorf("Submitted pod uses unsupported combination of '%s' annotation with '%s' mode", config.VaultInjectorAnnotationsFQ[vaultInjectorAnnotationLifecycleHookKey], job.VaultInjectorModeJob) - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + if context.ModesStatus[m.VaultInjectorModeJob] { + err = fmt.Errorf("Submitted pod uses unsupported combination of '%s' annotation with '%s' mode", config.VaultInjectorAnnotationsFQ[vaultInjectorAnnotationLifecycleHookKey], m.VaultInjectorModeJob) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return } if config.PodslifecycleHooks.PostStart != nil { if config.PodslifecycleHooks.PostStart.Exec == nil { err = errors.New("Unsupported lifecycle hook. Only support Exec type") - klog.Errorf("[%s] %s", VaultInjectorModeSecrets, err.Error()) + klog.Errorf("[%s] %s", m.VaultInjectorModeSecrets, err.Error()) return } @@ -117,7 +117,7 @@ func addLifecycleHooks(config *cfg.VSIConfig, podContainers []corev1.Container, if podCnt.Lifecycle != nil { if podCnt.Lifecycle.PostStart != nil { - klog.Warningf("[%s] Replacing existing postStart hook for container %s", VaultInjectorModeSecrets, podCnt.Name) + klog.Warningf("[%s] Replacing existing postStart hook for container %s", m.VaultInjectorModeSecrets, podCnt.Name) } podCnt.Lifecycle.PostStart = postStartHook diff --git a/pkg/mode/secrets/secrets.go b/pkg/mode/secrets/secrets.go index 52bf9d9..34fbf4b 100644 --- a/pkg/mode/secrets/secrets.go +++ b/pkg/mode/secrets/secrets.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ func init() { // Register mode m.RegisterMode( m.VaultInjectorModeInfo{ - Key: VaultInjectorModeSecrets, + Key: m.VaultInjectorModeSecrets, DefaultMode: true, // Secrets will be enabled if no mode explicitly set via mode annotation in manifest EnableDefaultMode: false, Annotations: []string{ diff --git a/pkg/mode/secrets/types.go b/pkg/mode/secrets/types.go index 9127b6c..444e532 100644 --- a/pkg/mode/secrets/types.go +++ b/pkg/mode/secrets/types.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pkg/mode/secrets/utils.go b/pkg/mode/secrets/utils.go index 8ea9840..4f94e91 100644 --- a/pkg/mode/secrets/utils.go +++ b/pkg/mode/secrets/utils.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Talend - www.talend.com +// Copyright © 2019-2021 Talend - www.talend.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package secrets import ( "errors" ctx "talend/vault-sidecar-injector/pkg/context" + m "talend/vault-sidecar-injector/pkg/mode" corev1 "k8s.io/api/core/v1" @@ -36,21 +37,21 @@ func getSecretsModeConfig(config ctx.ModeConfig) (*secretsModeConfig, error) { return nil, err } - err := errors.New("Null mode config") - klog.Error(err.Error()) + err := errors.New("Secrets mode config is null") + klog.Warning(err.Error()) return nil, err } -func isSecretsStatic(context *ctx.InjectionContext) bool { - if secretsModeCfg, err := getSecretsModeConfig(context.ModesConfig[VaultInjectorModeSecrets]); err == nil { +func IsSecretsStatic(context *ctx.InjectionContext) bool { + if secretsModeCfg, err := getSecretsModeConfig(context.ModesConfig[m.VaultInjectorModeSecrets]); err == nil { return secretsModeCfg.secretsType == vaultInjectorSecretsTypeStatic } return false } -func isSecretsInjectionEnv(context *ctx.InjectionContext) bool { - if secretsModeCfg, err := getSecretsModeConfig(context.ModesConfig[VaultInjectorModeSecrets]); err == nil { +func IsSecretsInjectionEnv(context *ctx.InjectionContext) bool { + if secretsModeCfg, err := getSecretsModeConfig(context.ModesConfig[m.VaultInjectorModeSecrets]); err == nil { return secretsModeCfg.secretsInjectionMethod == vaultInjectorSecretsInjectionMethodEnv } diff --git a/pkg/webhook/update-pod.go b/pkg/webhook/update-pod.go index d242889..a5a6130 100644 --- a/pkg/webhook/update-pod.go +++ b/pkg/webhook/update-pod.go @@ -23,7 +23,6 @@ import ( "talend/vault-sidecar-injector/pkg/config" ctx "talend/vault-sidecar-injector/pkg/context" m "talend/vault-sidecar-injector/pkg/mode" - "talend/vault-sidecar-injector/pkg/mode/job" "talend/vault-sidecar-injector/pkg/mode/secrets" corev1 "k8s.io/api/core/v1" @@ -78,9 +77,9 @@ func (vaultInjector *VaultInjector) computeContext(podContainers []corev1.Contai m.GetModesStatus(strings.Split(annotations[vaultInjector.VaultInjectorAnnotationsFQ[ctx.VaultInjectorAnnotationModeKey]], ","), modesStatus) // !!! This annotation is deprecated !!! Enable job mode if used - if annotations[vaultInjector.VaultInjectorAnnotationsFQ[ctx.VaultInjectorAnnotationWorkloadKey]] == job.VaultInjectorModeJob { + if annotations[vaultInjector.VaultInjectorAnnotationsFQ[ctx.VaultInjectorAnnotationWorkloadKey]] == m.VaultInjectorModeJob { klog.Warningf("Annotation '%s' is deprecated but still supported. Use '%s' instead", vaultInjector.VaultInjectorAnnotationsFQ[ctx.VaultInjectorAnnotationWorkloadKey], vaultInjector.VaultInjectorAnnotationsFQ[ctx.VaultInjectorAnnotationModeKey]) - modesStatus[job.VaultInjectorModeJob] = true + modesStatus[m.VaultInjectorModeJob] = true } klog.Infof("Modes status: %+v", modesStatus) diff --git a/samples/app-job-6-secrets_static-explicit_job_mode.yaml b/samples/app-job-6-secrets_static-explicit_job_mode.yaml new file mode 100644 index 0000000..4a176a5 --- /dev/null +++ b/samples/app-job-6-secrets_static-explicit_job_mode.yaml @@ -0,0 +1,72 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: job-sa + namespace: default +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: job-pod-status +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: job-pod-status +subjects: + - kind: ServiceAccount + name: job-sa +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: job-pod-status +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: app6-job + namespace: default +spec: + backoffLimit: 1 + template: + metadata: + annotations: + sidecar.vault.talend.org/inject: "true" + sidecar.vault.talend.org/secrets-type: "static" # static secrets + # When dealing with static secrets: no need to explicitly enable 'job' mode. You can remove annotation below + sidecar.vault.talend.org/mode: "job" # Explicitly enable 'job' mode (will also enable 'secrets' mode). + labels: + com.talend.application: test + com.talend.service: test-app-svc + spec: + restartPolicy: Never + # custom serviceAccountName with role allowing to perform GET on pods (needed to poll for job's pod status) + serviceAccountName: job-sa + containers: + - name: app6-job-container + image: busybox:1.28 + command: + - "sh" + - "-c" + - | + set -e + echo "Job started" + echo "I am a job... still working - 1" + cat /opt/talend/secrets/secrets.properties + sleep 5 + echo "I am a job... still working - 2" + cat /opt/talend/secrets/secrets.properties + sleep 5 + echo "I am a job... still working - 3" + cat /opt/talend/secrets/secrets.properties + sleep 5 + echo "I am a job... still working - 4" + cat /opt/talend/secrets/secrets.properties + sleep 5 + echo "I am a job... still working - 5" + cat /opt/talend/secrets/secrets.properties + echo "Job stopped" diff --git a/samples/app-job-7-secrets_static-proxy.yaml b/samples/app-job-7-secrets_static-proxy.yaml new file mode 100644 index 0000000..d64b34b --- /dev/null +++ b/samples/app-job-7-secrets_static-proxy.yaml @@ -0,0 +1,84 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: job-sa + namespace: default +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: job-pod-status +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get"] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: job-pod-status +subjects: + - kind: ServiceAccount + name: job-sa +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: job-pod-status +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: app7-job + namespace: default +spec: + backoffLimit: 1 + template: + metadata: + annotations: + sidecar.vault.talend.org/inject: "true" + sidecar.vault.talend.org/secrets-type: "static" # static secrets + sidecar.vault.talend.org/mode: "secrets,proxy,job" # Enable 'secrets', 'proxy' and 'job' modes + # Vault Sidecar Injector receive the pod spec: don't know whether it is a job or a deployment. + labels: + com.talend.application: test + com.talend.service: test-app-svc + spec: + restartPolicy: Never + # custom serviceAccountName with role allowing to perform GET on pods (needed to poll for job's pod status) + serviceAccountName: job-sa + containers: + - name: app7-job-container + image: everpeace/curl-jq + command: + - "sh" + - "-c" + - | + set -e + echo "Job started" + echo "Now using Vault Agent as a proxy to leverage Encryption as a Service feature (will encrypt and decrypt our secrets here)" + echo "Advantage: you do not need to deal with any Vault tokens and you just have to send requests to the local Vault Agent sidecar (available at 127.0.0.1) that will then forward everything to Vault server." + echo + + plaintext=$(cat /opt/talend/secrets/secrets.properties | grep SECRET1) + echo "Data that is going to be ciphered and deciphered: $plaintext" + echo + b64Plaintext=$(echo "$plaintext" | base64) + + isVaultReady=$(curl -s -X GET http://127.0.0.1:8200/v1/sys/health | jq --raw-output .initialized) + while [ "$isVaultReady" != "true" ];do + sleep 5 + isVaultReady=$(curl -s -X GET http://127.0.0.1:8200/v1/sys/health | jq --raw-output .initialized) + done + + ciphertext=$(curl -s -X POST --data "{\"plaintext\": \"$b64Plaintext\"}" http://127.0.0.1:8200/v1/transit/encrypt/test-key | jq --raw-output .data.ciphertext) + echo "Ciphertext" + echo "==========" + echo "$ciphertext" + echo + + cleartext=$(curl -s -X POST --data "{\"ciphertext\": \"$ciphertext\"}" http://127.0.0.1:8200/v1/transit/decrypt/test-key | jq --raw-output .data.plaintext) + echo "Cleartext" + echo "==========" + echo "$cleartext" | base64 -d + echo + echo "Job stopped" diff --git a/test/workloads/ok/test-app-job-6.yaml b/test/workloads/ok/test-app-job-6.yaml new file mode 100644 index 0000000..3175321 --- /dev/null +++ b/test/workloads/ok/test-app-job-6.yaml @@ -0,0 +1,52 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: test-app-job-secrets-static + namespace: default +spec: + backoffLimit: 1 + template: + metadata: + annotations: + sidecar.vault.talend.org/inject: "true" + sidecar.vault.talend.org/secrets-type: "static" # static secrets + # When dealing with static secrets: no need to enable 'job' mode. For this test, we explicitly declare it. + sidecar.vault.talend.org/mode: "job" + labels: + com.talend.application: test + com.talend.service: test-app-svc + spec: + restartPolicy: Never + # When dealing with static secrets: no need for a custom serviceAccountName + serviceAccountName: default + containers: + - name: test-app-job-secrets-static-container + image: busybox:1.28 + command: + - "sh" + - "-c" + - | + set -e + echo "Job started" + echo "I am a job... still working - 1" + cat /another-custom-folder/secrets.properties + sleep 5 + echo "I am a job... still working - 2" + cat /another-custom-folder/secrets.properties + sleep 5 + echo "I am a job... still working - 3" + cat /another-custom-folder/secrets.properties + sleep 5 + echo "I am a job... still working - 4" + cat /another-custom-folder/secrets.properties + sleep 5 + echo "I am a job... still working - 5" + cat /another-custom-folder/secrets.properties + echo "Job stopped" + volumeMounts: + - name: secrets + mountPath: /another-custom-folder + volumes: + - name: secrets + emptyDir: + medium: Memory \ No newline at end of file