1
0
Fork 0
mirror of https://github.com/external-secrets/external-secrets.git synced 2024-12-14 11:57:59 +00:00

Merge branch 'main' into feature/docs-versioning

This commit is contained in:
Gustavo Fernandes de Carvalho 2022-02-01 16:40:38 -03:00
commit 47a7425a2a
47 changed files with 1956 additions and 338 deletions

5
.github/codecov.yml vendored
View file

@ -1,5 +0,0 @@
ignore:
- pkg/provider/**/fake
coverage:
round: down
precision: 2

View file

@ -12,9 +12,7 @@ env:
# Common versions
GO_VERSION: '1.17'
GOLANGCI_VERSION: 'v1.42.1'
# list of available versions: https://storage.googleapis.com/kubebuilder-tools
# TODO: 1.21.2 does not shut down properly with controller-runtime 0.9.2
KUBEBUILDER_TOOLS_VERSION: '1.20.2'
KUBERNETES_VERSION: '1.23.x'
DOCKER_BUILDX_VERSION: 'v0.4.2'
# Common users. We can't run a step 'if secrets.GHCR_USERNAME != ""' but we can run
@ -164,22 +162,22 @@ jobs:
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-pkg-
- name: Add envtest binaries
run: |
curl -sSLo envtest-bins.tar.gz "https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-${{env.KUBEBUILDER_TOOLS_VERSION}}-linux-amd64.tar.gz"
sudo mkdir -p /usr/local/kubebuilder
sudo tar -C /usr/local/kubebuilder --strip-components=1 -zvxf envtest-bins.tar.gz
- name: Add setup-envtest
run: |
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
setup-envtest use ${{env.KUBERNETES_VERSION}} -p env --os $(go env GOOS) --arch $(go env GOARCH)
- name: Cache envtest binaries
uses: actions/cache@v2.1.7
with:
path: /usr/local/kubebuilder
key: ${{ runner.os }}-kubebuilder-${{env.KUBEBUILDER_TOOLS_VERSION}}
path: /home/runner/.local/share/kubebuilder-envtest/
key: ${{ runner.os }}-kubebuilder-${{env.KUBERNETES_VERSION}}
restore-keys: ${{ runner.os }}-kubebuilder-
- name: Run Unit Tests
run: |
export KUBEBUILDER_ATTACH_CONTROL_PLANE_OUTPUT=true
source <(setup-envtest use ${{env.KUBERNETES_VERSION}} -p env --os $(go env GOOS) --arch $(go env GOARCH))
make test

View file

@ -1,6 +1,5 @@
# Run secret-dependent e2e tests only after /ok-to-test-managed approval
on:
pull_request:
repository_dispatch:
types: [ok-to-test-managed-command]
@ -49,6 +48,48 @@ jobs:
steps:
# create new status check for this specific provider
- uses: actions/github-script@v1
if: ${{ always() }}
env:
number: ${{ github.event.client_payload.pull_request.number }}
provider: ${{ github.event.client_payload.slash_command.args.named.provider }}
job: ${{ github.job }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: pull } = await github.pulls.get({
...context.repo,
pull_number: process.env.number
});
const ref = pull.head.sha;
console.log("\n\nPR sha: " + ref)
const { data: checks } = await github.checks.listForRef({
...context.repo,
ref
});
const job_name = process.env.job + "-" + process.env.provider
console.log("\n\nPR CHECKS: " + checks)
const check = checks.check_runs.filter(c => c.name === job_name);
console.log("\n\nPR Filtered CHECK: " + check)
console.log(check)
if(check && check.length > 0){
const { data: result } = await github.checks.update({
...context.repo,
check_run_id: check[0].id,
status: 'in_progress',
});
return result;
}
const { data: result } = await github.checks.create({
...context.repo,
name: job_name,
head_sha: pull.head.sha,
status: 'in_progress',
});
return result;
# Check out merge commit
- name: Fork based /ok-to-test-managed checkout
uses: actions/checkout@v2
@ -164,6 +205,7 @@ jobs:
if: ${{ always() }}
env:
number: ${{ github.event.client_payload.pull_request.number }}
provider: ${{ github.event.client_payload.slash_command.args.named.provider }}
job: ${{ github.job }}
# Conveniently, job.status maps to https://developer.github.com/v3/checks/runs/#update-a-check-run
conclusion: ${{ job.status }}
@ -180,8 +222,9 @@ jobs:
...context.repo,
ref
});
const job_name = process.env.job + "-" + process.env.provider
console.log("\n\nPR CHECKS: " + checks)
const check = checks.check_runs.filter(c => c.name === process.env.job);
const check = checks.check_runs.filter(c => c.name === job_name);
console.log("\n\nPR Filtered CHECK: " + check)
console.log(check)
const { data: result } = await github.checks.update({

View file

@ -9,6 +9,8 @@ env:
GO_VERSION: '1.17'
GOLANGCI_VERSION: 'v1.33'
DOCKER_BUILDX_VERSION: 'v0.4.2'
KIND_VERSION: 'v0.11.1'
KIND_IMAGE: 'kindest/node:v1.23.3'
# Common users. We can't run a step 'if secrets.GHCR_USERNAME != ""' but we can run
# a step 'if env.GHCR_USERNAME' != ""', so we copy these to succinctly test whether
@ -71,9 +73,9 @@ jobs:
- name: Setup kind
uses: engineerd/setup-kind@v0.5.0
with:
version: "v0.11.1"
version: ${{env.KIND_VERSION}}
wait: 10m
node_image: kindest/node:v1.20.7
node_image: ${{env.KIND_IMAGE}}
name: external-secrets
- name: Setup Docker Buildx
@ -134,9 +136,9 @@ jobs:
- name: Setup kind
uses: engineerd/setup-kind@v0.5.0
with:
version: "v0.11.1"
version: ${{env.KIND_VERSION}}
wait: 10m
node_image: kindest/node:v1.20.7
node_image: ${{env.KIND_IMAGE}}
name: external-secrets
- name: Setup Docker Buildx

View file

@ -26,7 +26,7 @@ jobs:
make helm.generate
- name: Set up Helm
uses: azure/setup-helm@v1.1
uses: azure/setup-helm@v2.0
with:
version: v3.4.2
@ -62,7 +62,7 @@ jobs:
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Set up Helm
uses: azure/setup-helm@v1.1
uses: azure/setup-helm@v2.0
with:
version: v3.4.2

View file

@ -0,0 +1,27 @@
/*
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 v1alpha1
// FakeProvider configures a fake provider that returns static values.
type FakeProvider struct {
Data []FakeProviderData `json:"data"`
}
type FakeProviderData struct {
Key string `json:"key"`
Value string `json:"value,omitempty"`
ValueMap map[string]string `json:"valueMap,omitempty"`
Version string `json:"version,omitempty"`
}

View file

@ -81,6 +81,10 @@ type SecretStoreProvider struct {
// Webhook configures this store to sync secrets using a generic templated webhook
// +optional
Webhook *WebhookProvider `json:"webhook,omitempty"`
// Fake configures a store with static key/value pairs
// +optional
Fake *FakeProvider `json:"fake,omitempty"`
}
type SecretStoreRetrySettings struct {

View file

@ -599,6 +599,50 @@ func (in *ExternalSecretTemplateMetadata) DeepCopy() *ExternalSecretTemplateMeta
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FakeProvider) DeepCopyInto(out *FakeProvider) {
*out = *in
if in.Data != nil {
in, out := &in.Data, &out.Data
*out = make([]FakeProviderData, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeProvider.
func (in *FakeProvider) DeepCopy() *FakeProvider {
if in == nil {
return nil
}
out := new(FakeProvider)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *FakeProviderData) DeepCopyInto(out *FakeProviderData) {
*out = *in
if in.ValueMap != nil {
in, out := &in.ValueMap, &out.ValueMap
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FakeProviderData.
func (in *FakeProviderData) DeepCopy() *FakeProviderData {
if in == nil {
return nil
}
out := new(FakeProviderData)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GCPSMAuth) DeepCopyInto(out *GCPSMAuth) {
*out = *in
@ -939,6 +983,11 @@ func (in *SecretStoreProvider) DeepCopyInto(out *SecretStoreProvider) {
*out = new(WebhookProvider)
(*in).DeepCopyInto(*out)
}
if in.Fake != nil {
in, out := &in.Fake, &out.Fake
*out = new(FakeProvider)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretStoreProvider.

View file

@ -380,6 +380,29 @@ spec:
required:
- vaultUrl
type: object
fake:
description: Fake configures a store with static key/value pairs
properties:
data:
items:
properties:
key:
type: string
value:
type: string
valueMap:
additionalProperties:
type: string
type: object
version:
type: string
required:
- key
type: object
type: array
required:
- data
type: object
gcpsm:
description: GCPSM configures this store to sync secrets using
Google Cloud Platform Secret Manager provider

View file

@ -380,6 +380,29 @@ spec:
required:
- vaultUrl
type: object
fake:
description: Fake configures a store with static key/value pairs
properties:
data:
items:
properties:
key:
type: string
value:
type: string
valueMap:
additionalProperties:
type: string
type: object
version:
type: string
required:
- key
type: object
type: array
required:
- data
type: object
gcpsm:
description: GCPSM configures this store to sync secrets using
Google Cloud Platform Secret Manager provider

View file

@ -31,6 +31,82 @@ for the lifecycle of the PR: review, merging, ping on inactivity, close.
We close pull requests or issues if there is no response from the author for
a period of time. Feel free to reopen if you want to get back on it.
### Triggering e2e tests
We have an extensive set of e2e tests that test the integration with *real* cloud provider APIs.
Maintainers must trigger these kind of tests manually for PRs that come from forked repositories. These tests run inside a `kind` cluster in the GitHub Actions runner:
```
/ok-to-test sha=xxxxxx
```
#### Executing e2e tests locally
You have to prepare your shell environment with the necessary variables so the e2e test
runner knows what credentials to use. See `e2e/run.sh` for the variables that are passed in.
If you e.g. want to test AWS integration make sure set all `AWS_*` variables mentioned
in that file.
Use [ginkgo labels](https://onsi.github.io/ginkgo/#spec-labels) to select the tests
you want to execute. You have to specify `!managed` to ensure that you do not
run managed tests.
```
make test.e2e GINKGO_LABELS='gcp&&!managed'
```
#### Managed Kubernetes e2e tests
There's another suite of e2e tests that integrate with managed Kuberentes offerings.
They create real infrastructure at a cloud provider and deploy the controller
into that environment.
This is necessary to test the authentication integration
([GCP Worklaod Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity),
[EKS IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html)...).
These tests are time intensive (~20-45min) and must be triggered manually by
a maintainer when a particular provider or authentication mechanism was changed:
```
/ok-to-test-managed sha=xxxxxx provider=aws
# or
/ok-to-test-managed sha=xxxxxx provider=gcp
```
Both tests can run in parallel. Once started they add a dynamic GitHub check `integration-managed-(gcp|aws)` to the PR that triggered the test.
### Executing Managed Kubernetes e2e tests locally
You have to prepare your shell environment with the necessary variables so the e2e
test runner knows what credentials to use. See `.github/workflows/e2e-managed.yml`
for the variables that are passed in. If you e.g. want to test AWS integration make
sure set all variables containing `AWS_*` and `TF_VAR_AWS_*` mentioned in that file.
Then execute `tf.apply.aws` or `tf.apply.gcp` to create the infrastructure.
```
make tf.apply.aws
```
Then run the `managed` testsuite. You will need push permissions to the external-secrets ghcr repository. You can set `IMAGE_REGISTRY` to control which image registry is used to store the controller and e2e test images in.
You also have to setup a proper Kubeconfig so the e2e test pod gets deployed into the managed cluster.
```
aws eks update-kubeconfig --name ${AWS_CLUSTER_NAME}
or
gcloud container clusters get-credentials ${GCP_GKE_CLUSTER} --region europe-west1-b
```
Use [ginkgo labels](https://onsi.github.io/ginkgo/#spec-labels) to select the tests
you want to execute.
```
# you may have to set IMAGE_REGISTRY=docker.io/your-user/external-secrets
make test.e2e.managed GINKGO_LABELS='gcp'
```
## Proposal Process
Before we introduce significant changes to the project we want to gather feedback
from the community to ensure that we progress in the right direction before we

26
docs/provider-fake.md Normal file
View file

@ -0,0 +1,26 @@
We provide a `fake` implementation to help with testing. This provider returns static key/value pairs and nothing else.
To use the `fake` provider simply create a `SecretStore` or `ClusterSecretStore` and configure it like in the following example:
!!! note inline end
The provider returns static data configured in `value` or `valueMap`. You can define a `version`, too. If set the `remoteRef` from an ExternalSecret must match otherwise no value is returned.
```yaml
{% include 'fake-provider-store.yaml' %}
```
Please note that `value` is intended for exclusive use with `data` and `valueMap` for `dataFrom`.
Here is an example `ExternalSecret` that displays this behavior:
!!! warning inline end
This provider supports specifying different `data[].version` configurations. However, `data[].property` is ignored.
```yaml
{% include 'fake-provider-es.yaml' %}
```
This results in the following secret:
```yaml
{% include 'fake-provider-secret.yaml' %}
```

View file

@ -0,0 +1,18 @@
apiVersion: external-secrets.io/v1alpha1
kind: ExternalSecret
metadata:
name: example
spec:
refreshInterval: 1h
secretStoreRef:
name: fake
kind: ClusterSecretStore
target:
name: secret-to-be-created
data:
- secretKey: foo_bar
remoteRef:
key: /foo/bar
version: v1
dataFrom:
- key: /foo/baz

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: secret-to-be-created
namespace: default
data:
foo_bar: SEVMTE8x # HELLO1 (via data)
foo: ZXhhbXBsZQ== # example (via dataFrom)
other: dGhpbmc= # thing (via dataFrom)

View file

@ -0,0 +1,20 @@
apiVersion: external-secrets.io/v1alpha1
kind: ClusterSecretStore
metadata:
name: fake
spec:
provider:
fake:
data:
- key: "/foo/bar"
value: "HELLO1"
version: "v1"
- key: "/foo/bar"
value: "HELLO2"
version: "v2"
- key: "/foo/baz"
valueMap:
foo: example
other: thing

View file

@ -714,6 +714,237 @@ string
<td></td>
</tr></tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecret">ClusterExternalSecret
</h3>
<p>
<p>ClusterExternalSecret is the Schema for the clusterexternalsecrets API.</p>
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>metadata</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta">
Kubernetes meta/v1.ObjectMeta
</a>
</em>
</td>
<td>
Refer to the Kubernetes API documentation for the fields of the
<code>metadata</code> field.
</td>
</tr>
<tr>
<td>
<code>spec</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretSpec">
ClusterExternalSecretSpec
</a>
</em>
</td>
<td>
<br/>
<br/>
<table>
<tr>
<td>
<code>externalSecretSpec</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.ExternalSecretSpec">
ExternalSecretSpec
</a>
</em>
</td>
<td>
<p>The spec for the ExternalSecrets to be created</p>
</td>
</tr>
<tr>
<td>
<code>externalSecretName</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the external secrets to be created defaults to the name of the ClusterExternalSecret</p>
</td>
</tr>
<tr>
<td>
<code>namespaceSelector</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#labelselector-v1-meta">
Kubernetes meta/v1.LabelSelector
</a>
</em>
</td>
<td>
<p>The labels to select by to find the Namespaces to create the ExternalSecrets in.</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<code>status</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretStatus">
ClusterExternalSecretStatus
</a>
</em>
</td>
<td>
</td>
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecretConditionType">ClusterExternalSecretConditionType
(<code>string</code> alias)</p></h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretStatus">ClusterExternalSecretStatus</a>)
</p>
<p>
</p>
<table>
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr><td><p>&#34;NotReady&#34;</p></td>
<td></td>
</tr><tr><td><p>&#34;PartiallyReady&#34;</p></td>
<td></td>
</tr><tr><td><p>&#34;Ready&#34;</p></td>
<td></td>
</tr></tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecretSpec">ClusterExternalSecretSpec
</h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecret">ClusterExternalSecret</a>)
</p>
<p>
<p>ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret.</p>
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>externalSecretSpec</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.ExternalSecretSpec">
ExternalSecretSpec
</a>
</em>
</td>
<td>
<p>The spec for the ExternalSecrets to be created</p>
</td>
</tr>
<tr>
<td>
<code>externalSecretName</code></br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>The name of the external secrets to be created defaults to the name of the ClusterExternalSecret</p>
</td>
</tr>
<tr>
<td>
<code>namespaceSelector</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#labelselector-v1-meta">
Kubernetes meta/v1.LabelSelector
</a>
</em>
</td>
<td>
<p>The labels to select by to find the Namespaces to create the ExternalSecrets in.</p>
</td>
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.ClusterExternalSecretStatus">ClusterExternalSecretStatus
</h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecret">ClusterExternalSecret</a>)
</p>
<p>
<p>ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret.</p>
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>type</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretConditionType">
ClusterExternalSecretConditionType
</a>
</em>
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>status</code></br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#conditionstatus-v1-core">
Kubernetes core/v1.ConditionStatus
</a>
</em>
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>externalSecretStatuses</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.ExternalSecretStatus">
[]ExternalSecretStatus
</a>
</em>
</td>
<td>
<em>(Optional)</em>
</td>
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.ClusterSecretStore">ClusterSecretStore
</h3>
<p>
@ -1084,6 +1315,7 @@ string
</h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretSpec">ClusterExternalSecretSpec</a>,
<a href="#external-secrets.io/v1alpha1.ExternalSecret">ExternalSecret</a>)
</p>
<p>
@ -1171,6 +1403,7 @@ If multiple entries are specified, the Secret keys are merged in the specified o
</h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.ClusterExternalSecretStatus">ClusterExternalSecretStatus</a>,
<a href="#external-secrets.io/v1alpha1.ExternalSecret">ExternalSecret</a>)
</p>
<p>
@ -1486,6 +1719,95 @@ map[string]string
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.FakeProvider">FakeProvider
</h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.SecretStoreProvider">SecretStoreProvider</a>)
</p>
<p>
<p>FakeProvider configures a fake provider that returns static values</p>
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>data</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.FakeProviderData">
[]FakeProviderData
</a>
</em>
</td>
<td>
</td>
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.FakeProviderData">FakeProviderData
</h3>
<p>
(<em>Appears on:</em>
<a href="#external-secrets.io/v1alpha1.FakeProvider">FakeProvider</a>)
</p>
<p>
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>key</code></br>
<em>
string
</em>
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>value</code></br>
<em>
string
</em>
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>valueMap</code></br>
<em>
map[string]string
</em>
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>version</code></br>
<em>
string
</em>
</td>
<td>
</td>
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.GCPSMAuth">GCPSMAuth
</h3>
<p>
@ -2310,6 +2632,20 @@ WebhookProvider
<p>Webhook configures this store to sync secrets using a generic templated webhook</p>
</td>
</tr>
<tr>
<td>
<code>fake</code></br>
<em>
<a href="#external-secrets.io/v1alpha1.FakeProvider">
FakeProvider
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Fake configures a store with static key/value pairs</p>
</td>
</tr>
</tbody>
</table>
<h3 id="external-secrets.io/v1alpha1.SecretStoreRef">SecretStoreRef

View file

@ -2,7 +2,7 @@ MAKEFLAGS += --warn-undefined-variables
SHELL := /bin/bash
.SHELLFLAGS := -euo pipefail -c
KIND_IMG = "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"
KIND_IMG = "kindest/node:v1.23.3@sha256:0df8215895129c0d3221cda19847d1296c4f29ec93487339149333bd9d899e5a"
BUILD_ARGS ?=
export E2E_IMAGE_REGISTRY ?= ghcr.io/external-secrets/external-secrets-e2e

97
e2e/suite/aws/common.go Normal file
View file

@ -0,0 +1,97 @@
/*
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 common
import (
"context"
// nolint
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/e2e/framework"
)
const (
WithReferencedIRSA = "with referenced IRSA"
WithMountedIRSA = "with mounted IRSA"
StaticCredentialsSecretName = "provider-secret"
)
func ReferencedIRSAStoreName(f *framework.Framework) string {
return "irsa-ref-" + f.Namespace.Name
}
func MountedIRSAStoreName(f *framework.Framework) string {
return "irsa-mounted-" + f.Namespace.Name
}
func UseClusterSecretStore(tc *framework.TestCase) {
tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind
tc.ExternalSecret.Spec.SecretStoreRef.Name = ReferencedIRSAStoreName(tc.Framework)
}
func UseMountedIRSAStore(tc *framework.TestCase) {
tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.SecretStoreKind
tc.ExternalSecret.Spec.SecretStoreRef.Name = MountedIRSAStoreName(tc.Framework)
}
// StaticStore is namespaced and references
// static credentials from a secret.
func SetupStaticStore(f *framework.Framework, kid, sak, region string, serviceType esv1alpha1.AWSServiceType) {
awsCreds := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: StaticCredentialsSecretName,
Namespace: f.Namespace.Name,
},
StringData: map[string]string{
"kid": kid,
"sak": sak,
},
}
err := f.CRClient.Create(context.Background(), awsCreds)
Expect(err).ToNot(HaveOccurred())
secretStore := &esv1alpha1.SecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: f.Namespace.Name,
Namespace: f.Namespace.Name,
},
Spec: esv1alpha1.SecretStoreSpec{
Provider: &esv1alpha1.SecretStoreProvider{
AWS: &esv1alpha1.AWSProvider{
Service: serviceType,
Region: region,
Auth: esv1alpha1.AWSAuth{
SecretRef: &esv1alpha1.AWSAuthSecretRef{
AccessKeyID: esmetav1.SecretKeySelector{
Name: StaticCredentialsSecretName,
Key: "kid",
},
SecretAccessKey: esmetav1.SecretKeySelector{
Name: StaticCredentialsSecretName,
Key: "sak",
},
},
},
},
},
},
}
err = f.CRClient.Create(context.Background(), secretStore)
Expect(err).ToNot(HaveOccurred())
}

View file

@ -0,0 +1,45 @@
/*
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 aws
import (
// nolint
. "github.com/onsi/ginkgo/v2"
"github.com/external-secrets/external-secrets/e2e/framework"
"github.com/external-secrets/external-secrets/e2e/suite/common"
)
var _ = Describe("[aws] ", Label("aws", "parameterstore"), func() {
f := framework.New("eso-aws-ps")
prov := NewFromEnv(f)
DescribeTable("sync secrets",
framework.TableFunc(f,
prov),
Entry(common.SimpleDataSync(f)),
Entry(common.NestedJSONWithGJSON(f)),
Entry(common.JSONDataFromSync(f)),
Entry(common.JSONDataWithProperty(f)),
Entry(common.JSONDataWithTemplate(f)),
Entry(common.DockerJSONConfig(f)),
Entry(common.DataPropertyDockerconfigJSON(f)),
Entry(common.SSHKeySync(f)),
Entry(common.SSHKeySyncDataProperty(f)),
Entry(common.SyncWithoutTargetName(f)),
Entry(common.JSONDataWithoutTargetName(f)),
)
})

View file

@ -0,0 +1,85 @@
/*
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 aws
import (
// nolint
. "github.com/onsi/ginkgo/v2"
"github.com/external-secrets/external-secrets/e2e/framework"
"github.com/external-secrets/external-secrets/e2e/framework/addon"
awscommon "github.com/external-secrets/external-secrets/e2e/suite/aws"
"github.com/external-secrets/external-secrets/e2e/suite/common"
)
// here we use the global eso instance
// that uses the service account in the default namespace
// which was created by terraform.
var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "parameterstore", "managed"), func() {
f := framework.New("eso-aws-ps-managed")
prov := NewFromEnv(f)
// nolint
DescribeTable("sync secrets",
framework.TableFunc(f,
prov),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SimpleDataSync, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataFromSync, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithProperty, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithTemplate, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.DockerJSONConfig, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySync, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SyncWithoutTargetName, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseClusterSecretStore),
)
})
// here we create a central eso instance in the default namespace
// that mounts the service account which was created by terraform.
var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "parameterstore", "managed"), func() {
f := framework.New("eso-aws-ps-irsa-managed")
prov := NewFromEnv(f)
// each test case gets its own ESO instance
BeforeEach(func() {
f.Install(addon.NewESO(
addon.WithControllerClass(f.BaseName),
addon.WithServiceAccount(prov.ServiceAccountName),
addon.WithReleaseName(f.Namespace.Name),
addon.WithNamespace("default"),
))
})
// nolint
DescribeTable("sync secrets",
framework.TableFunc(f,
prov),
framework.Compose(awscommon.WithMountedIRSA, f, common.SimpleDataSync, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataFromSync, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithProperty, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithTemplate, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.DockerJSONConfig, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySync, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.SyncWithoutTargetName, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseMountedIRSAStore),
)
})

View file

@ -0,0 +1,165 @@
/*
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 aws
import (
"context"
"os"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ssm"
//nolint
. "github.com/onsi/ginkgo/v2"
// nolint
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/e2e/framework"
"github.com/external-secrets/external-secrets/e2e/framework/log"
common "github.com/external-secrets/external-secrets/e2e/suite/aws"
)
type Provider struct {
ServiceAccountName string
ServiceAccountNamespace string
region string
client *ssm.SSM
framework *framework.Framework
}
func NewProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *Provider {
sess, err := session.NewSessionWithOptions(session.Options{
Config: aws.Config{
Credentials: credentials.NewStaticCredentials(kid, sak, ""),
Region: aws.String(region),
},
})
if err != nil {
Fail(err.Error())
}
sm := ssm.New(sess)
prov := &Provider{
ServiceAccountName: saName,
ServiceAccountNamespace: saNamespace,
region: region,
client: sm,
framework: f,
}
BeforeEach(func() {
common.SetupStaticStore(f, kid, sak, region, esv1alpha1.AWSServiceParameterStore)
prov.SetupReferencedIRSAStore()
prov.SetupMountedIRSAStore()
})
AfterEach(func() {
// Cleanup ClusterSecretStore
err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: common.ReferencedIRSAStoreName(f),
},
})
Expect(err).ToNot(HaveOccurred())
})
return prov
}
func NewFromEnv(f *framework.Framework) *Provider {
kid := os.Getenv("AWS_ACCESS_KEY_ID")
sak := os.Getenv("AWS_SECRET_ACCESS_KEY")
region := "eu-west-1"
saName := os.Getenv("AWS_SA_NAME")
saNamespace := os.Getenv("AWS_SA_NAMESPACE")
return NewProvider(f, kid, sak, region, saName, saNamespace)
}
// CreateSecret creates a secret at the provider.
func (s *Provider) CreateSecret(key, val string) {
_, err := s.client.PutParameter(&ssm.PutParameterInput{
Name: aws.String(key),
Value: aws.String(val),
DataType: aws.String("text"),
Type: aws.String("String"),
})
Expect(err).ToNot(HaveOccurred())
}
// DeleteSecret deletes a secret at the provider.
func (s *Provider) DeleteSecret(key string) {
_, err := s.client.DeleteParameter(&ssm.DeleteParameterInput{
Name: aws.String(key),
})
Expect(err).ToNot(HaveOccurred())
}
// MountedIRSAStore is a SecretStore without auth config
// ESO relies on the pod-mounted ServiceAccount when using this store.
func (s *Provider) SetupMountedIRSAStore() {
secretStore := &esv1alpha1.SecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: common.MountedIRSAStoreName(s.framework),
Namespace: s.framework.Namespace.Name,
},
Spec: esv1alpha1.SecretStoreSpec{
Provider: &esv1alpha1.SecretStoreProvider{
AWS: &esv1alpha1.AWSProvider{
Service: esv1alpha1.AWSServiceParameterStore,
Region: s.region,
Auth: esv1alpha1.AWSAuth{},
},
},
},
}
err := s.framework.CRClient.Create(context.Background(), secretStore)
Expect(err).ToNot(HaveOccurred())
}
// ReferncedIRSAStore is a ClusterStore
// that references a (IRSA-) ServiceAccount in the default namespace.
func (s *Provider) SetupReferencedIRSAStore() {
log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name)
secretStore := &esv1alpha1.ClusterSecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: common.ReferencedIRSAStoreName(s.framework),
},
}
_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error {
secretStore.Spec.Provider = &esv1alpha1.SecretStoreProvider{
AWS: &esv1alpha1.AWSProvider{
Service: esv1alpha1.AWSServiceParameterStore,
Region: s.region,
Auth: esv1alpha1.AWSAuth{
JWTAuth: &esv1alpha1.AWSJWTAuth{
ServiceAccountRef: &esmetav1.ServiceAccountSelector{
Name: s.ServiceAccountName,
Namespace: &s.ServiceAccountNamespace,
},
},
},
},
}
return nil
})
Expect(err).ToNot(HaveOccurred())
}

View file

@ -29,7 +29,6 @@ import (
// nolint
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@ -37,24 +36,19 @@ import (
esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
"github.com/external-secrets/external-secrets/e2e/framework"
"github.com/external-secrets/external-secrets/e2e/framework/log"
common "github.com/external-secrets/external-secrets/e2e/suite/aws"
)
type SMProvider struct {
type Provider struct {
ServiceAccountName string
ServiceAccountNamespace string
kid string
sak string
region string
client *secretsmanager.SecretsManager
framework *framework.Framework
}
const (
staticCredentialsSecretName = "provider-secret"
)
func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *SMProvider {
func NewProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *Provider {
sess, err := session.NewSessionWithOptions(session.Options{
Config: aws.Config{
Credentials: credentials.NewStaticCredentials(kid, sak, ""),
@ -65,18 +59,16 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace
Fail(err.Error())
}
sm := secretsmanager.New(sess)
prov := &SMProvider{
prov := &Provider{
ServiceAccountName: saName,
ServiceAccountNamespace: saNamespace,
kid: kid,
sak: sak,
region: region,
client: sm,
framework: f,
}
BeforeEach(func() {
prov.SetupStaticStore()
common.SetupStaticStore(f, kid, sak, region, esv1alpha1.AWSServiceSecretsManager)
prov.SetupReferencedIRSAStore()
prov.SetupMountedIRSAStore()
})
@ -85,7 +77,7 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace
// Cleanup ClusterSecretStore
err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: prov.ReferencedIRSAStoreName(),
Name: common.ReferencedIRSAStoreName(f),
},
})
Expect(err).ToNot(HaveOccurred())
@ -94,17 +86,17 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace
return prov
}
func NewFromEnv(f *framework.Framework) *SMProvider {
func NewFromEnv(f *framework.Framework) *Provider {
kid := os.Getenv("AWS_ACCESS_KEY_ID")
sak := os.Getenv("AWS_SECRET_ACCESS_KEY")
region := "eu-west-1"
saName := os.Getenv("AWS_SA_NAME")
saNamespace := os.Getenv("AWS_SA_NAMESPACE")
return NewSMProvider(f, kid, sak, region, saName, saNamespace)
return NewProvider(f, kid, sak, region, saName, saNamespace)
}
// CreateSecret creates a secret at the provider.
func (s *SMProvider) CreateSecret(key, val string) {
func (s *Provider) CreateSecret(key, val string) {
// we re-use some secret names throughout our test suite
// due to the fact that there is a short delay before the secret is actually deleted
// we have to retry creating the secret
@ -129,7 +121,7 @@ func (s *SMProvider) CreateSecret(key, val string) {
// DeleteSecret deletes a secret at the provider.
// There may be a short delay between calling this function
// and the removal of the secret on the provider side.
func (s *SMProvider) DeleteSecret(key string) {
func (s *Provider) DeleteSecret(key string) {
log.Logf("deleting secret %s", key)
_, err := s.client.DeleteSecret(&secretsmanager.DeleteSecretInput{
SecretId: aws.String(key),
@ -140,10 +132,10 @@ func (s *SMProvider) DeleteSecret(key string) {
// MountedIRSAStore is a SecretStore without auth config
// ESO relies on the pod-mounted ServiceAccount when using this store.
func (s *SMProvider) SetupMountedIRSAStore() {
func (s *Provider) SetupMountedIRSAStore() {
secretStore := &esv1alpha1.SecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: s.MountedIRSAStoreName(),
Name: common.MountedIRSAStoreName(s.framework),
Namespace: s.framework.Namespace.Name,
},
Spec: esv1alpha1.SecretStoreSpec{
@ -160,17 +152,13 @@ func (s *SMProvider) SetupMountedIRSAStore() {
Expect(err).ToNot(HaveOccurred())
}
func (s *SMProvider) MountedIRSAStoreName() string {
return "irsa-mounted-" + s.framework.Namespace.Name
}
// ReferncedIRSAStore is a ClusterStore
// that references a (IRSA-) ServiceAccount in the default namespace.
func (s *SMProvider) SetupReferencedIRSAStore() {
func (s *Provider) SetupReferencedIRSAStore() {
log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name)
secretStore := &esv1alpha1.ClusterSecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: s.ReferencedIRSAStoreName(),
Name: common.ReferencedIRSAStoreName(s.framework),
},
}
_, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error {
@ -192,53 +180,3 @@ func (s *SMProvider) SetupReferencedIRSAStore() {
})
Expect(err).ToNot(HaveOccurred())
}
func (s *SMProvider) ReferencedIRSAStoreName() string {
return "irsa-ref-" + s.framework.Namespace.Name
}
// StaticStore is namespaced and references
// static credentials from a secret.
func (s *SMProvider) SetupStaticStore() {
awsCreds := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: staticCredentialsSecretName,
Namespace: s.framework.Namespace.Name,
},
StringData: map[string]string{
"kid": s.kid,
"sak": s.sak,
},
}
err := s.framework.CRClient.Create(context.Background(), awsCreds)
Expect(err).ToNot(HaveOccurred())
secretStore := &esv1alpha1.SecretStore{
ObjectMeta: metav1.ObjectMeta{
Name: s.framework.Namespace.Name,
Namespace: s.framework.Namespace.Name,
},
Spec: esv1alpha1.SecretStoreSpec{
Provider: &esv1alpha1.SecretStoreProvider{
AWS: &esv1alpha1.AWSProvider{
Service: esv1alpha1.AWSServiceSecretsManager,
Region: s.region,
Auth: esv1alpha1.AWSAuth{
SecretRef: &esv1alpha1.AWSAuthSecretRef{
AccessKeyID: esmetav1.SecretKeySelector{
Name: staticCredentialsSecretName,
Key: "kid",
},
SecretAccessKey: esmetav1.SecretKeySelector{
Name: staticCredentialsSecretName,
Key: "sak",
},
},
},
},
},
},
}
err = s.framework.CRClient.Create(context.Background(), secretStore)
Expect(err).ToNot(HaveOccurred())
}

View file

@ -0,0 +1,85 @@
/*
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 aws
import (
// nolint
. "github.com/onsi/ginkgo/v2"
"github.com/external-secrets/external-secrets/e2e/framework"
"github.com/external-secrets/external-secrets/e2e/framework/addon"
awscommon "github.com/external-secrets/external-secrets/e2e/suite/aws"
"github.com/external-secrets/external-secrets/e2e/suite/common"
)
// here we use the global eso instance
// that uses the service account in the default namespace
// which was created by terraform.
var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "secretsmanager", "managed"), func() {
f := framework.New("eso-aws-managed")
prov := NewFromEnv(f)
// nolint
DescribeTable("sync secretsmanager secrets",
framework.TableFunc(f,
prov),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SimpleDataSync, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataFromSync, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithProperty, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithTemplate, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.DockerJSONConfig, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySync, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.SyncWithoutTargetName, awscommon.UseClusterSecretStore),
framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseClusterSecretStore),
)
})
// here we create a central eso instance in the default namespace
// that mounts the service account which was created by terraform.
var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "secretsmanager", "managed"), func() {
f := framework.New("eso-aws-managed")
prov := NewFromEnv(f)
// each test case gets its own ESO instance
BeforeEach(func() {
f.Install(addon.NewESO(
addon.WithControllerClass(f.BaseName),
addon.WithServiceAccount(prov.ServiceAccountName),
addon.WithReleaseName(f.Namespace.Name),
addon.WithNamespace("default"),
))
})
// nolint
DescribeTable("sync secretsmanager secrets",
framework.TableFunc(f,
prov),
framework.Compose(awscommon.WithMountedIRSA, f, common.SimpleDataSync, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataFromSync, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithProperty, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithTemplate, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.DockerJSONConfig, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySync, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.SyncWithoutTargetName, awscommon.UseMountedIRSAStore),
framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseMountedIRSAStore),
)
})

View file

@ -1,102 +0,0 @@
/*
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 aws
import (
// nolint
. "github.com/onsi/ginkgo/v2"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
"github.com/external-secrets/external-secrets/e2e/framework"
"github.com/external-secrets/external-secrets/e2e/framework/addon"
"github.com/external-secrets/external-secrets/e2e/suite/common"
)
const (
withReferencedIRSA = "with referenced IRSA"
withMountedIRSA = "with mounted IRSA"
)
// here we use the global eso instance
// that uses the service account in the default namespace
// which was created by terraform.
var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "secretsmanager", "managed"), func() {
f := framework.New("eso-aws-managed")
prov := NewFromEnv(f)
DescribeTable("sync secrets",
framework.TableFunc(f,
prov),
framework.Compose(withReferencedIRSA, f, common.SimpleDataSync, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.NestedJSONWithGJSON, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.JSONDataFromSync, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.JSONDataWithProperty, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.JSONDataWithTemplate, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.DockerJSONConfig, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.DataPropertyDockerconfigJSON, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.SSHKeySync, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.SSHKeySyncDataProperty, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.SyncWithoutTargetName, useClusterSecretStore(prov)),
framework.Compose(withReferencedIRSA, f, common.JSONDataWithoutTargetName, useClusterSecretStore(prov)),
)
})
// here we create a central eso instance in the default namespace
// that mounts the service account which was created by terraform.
var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "secretsmanager", "managed"), func() {
f := framework.New("eso-aws-managed")
prov := NewFromEnv(f)
// each test case gets its own ESO instance
BeforeEach(func() {
f.Install(addon.NewESO(
addon.WithControllerClass(f.BaseName),
addon.WithServiceAccount(prov.ServiceAccountName),
addon.WithReleaseName(f.Namespace.Name),
addon.WithNamespace("default"),
))
})
DescribeTable("sync secrets",
framework.TableFunc(f,
prov),
framework.Compose(withMountedIRSA, f, common.SimpleDataSync, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.NestedJSONWithGJSON, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.JSONDataFromSync, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.JSONDataWithProperty, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.JSONDataWithTemplate, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.DockerJSONConfig, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.DataPropertyDockerconfigJSON, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.SSHKeySync, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.SSHKeySyncDataProperty, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.SyncWithoutTargetName, useMountedIRSAStore(prov)),
framework.Compose(withMountedIRSA, f, common.JSONDataWithoutTargetName, useMountedIRSAStore(prov)),
)
})
func useClusterSecretStore(prov *SMProvider) func(*framework.TestCase) {
return func(tc *framework.TestCase) {
tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind
tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.ReferencedIRSAStoreName()
}
}
func useMountedIRSAStore(prov *SMProvider) func(*framework.TestCase) {
return func(tc *framework.TestCase) {
tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.SecretStoreKind
tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.MountedIRSAStoreName()
}
}

View file

@ -0,0 +1,66 @@
/*
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.
limitations under the License.
*/
package azure
import (
"fmt"
// nolint
. "github.com/onsi/ginkgo/v2"
v1 "k8s.io/api/core/v1"
// nolint
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
"github.com/external-secrets/external-secrets/e2e/framework"
)
// azure keyvault type=cert should get a certificate from the api.
var _ = Describe("[azure]", Label("azure", "keyvault", "cert"), func() {
f := framework.New("eso-azure-certtype")
prov := newFromEnv(f)
var certBytes []byte
var certName string
BeforeEach(func() {
certName = fmt.Sprintf("%s-%s", f.Namespace.Name, "certtest")
prov.CreateCertificate(certName)
certBytes = prov.GetCertificate(certName)
})
AfterEach(func() {
prov.DeleteCertificate(certName)
})
ff := framework.TableFunc(f, prov)
It("should sync keyvault objects with type=cert", func() {
ff(func(tc *framework.TestCase) {
secretKey := "azkv-cert"
tc.ExpectedSecret = &v1.Secret{
Type: v1.SecretTypeOpaque,
Data: map[string][]byte{
secretKey: certBytes,
},
}
tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
{
SecretKey: secretKey,
RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
Key: "cert/" + certName,
},
},
}
})
})
})

View file

@ -0,0 +1,69 @@
/*
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.
limitations under the License.
*/
package azure
import (
"encoding/json"
"fmt"
"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
// nolint
. "github.com/onsi/ginkgo/v2"
v1 "k8s.io/api/core/v1"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
"github.com/external-secrets/external-secrets/e2e/framework"
)
// azure keyvault type=key should retrieve a jwk from the api.
var _ = Describe("[azure]", Label("azure", "keyvault", "key"), func() {
f := framework.New("eso-azure-keytype")
prov := newFromEnv(f)
var jwk *keyvault.JSONWebKey
var keyName string
BeforeEach(func() {
keyName = fmt.Sprintf("%s-%s", f.Namespace.Name, "keytest")
jwk = prov.CreateKey(keyName)
})
AfterEach(func() {
prov.DeleteKey(keyName)
})
ff := framework.TableFunc(f, prov)
It("should sync keyvault objects with type=key", func() {
ff(func(tc *framework.TestCase) {
secretKey := "azkv-key"
keyBytes, _ := json.Marshal(jwk)
tc.ExpectedSecret = &v1.Secret{
Type: v1.SecretTypeOpaque,
Data: map[string][]byte{
secretKey: keyBytes,
},
}
tc.ExternalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{
{
SecretKey: secretKey,
RemoteRef: esv1alpha1.ExternalSecretDataRemoteRef{
Key: "key/" + keyName,
},
},
}
})
})
})

View file

@ -21,7 +21,8 @@ import (
"github.com/external-secrets/external-secrets/e2e/suite/common"
)
var _ = Describe("[azure]", Label("azure", "keyvault"), func() {
// keyvault type=secret should behave just like any other secret store.
var _ = Describe("[azure]", Label("azure", "keyvault", "secret"), func() {
f := framework.New("eso-azure")
prov := newFromEnv(f)

View file

@ -15,16 +15,15 @@ package azure
import (
"context"
"os"
"time"
"github.com/Azure/azure-sdk-for-go/profiles/latest/keyvault/keyvault"
kvauth "github.com/Azure/go-autorest/autorest/azure/auth"
// nolint
. "github.com/onsi/gomega"
// nolint
. "github.com/onsi/ginkgo/v2"
// nolint
. "github.com/onsi/gomega"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilpointer "k8s.io/utils/pointer"
@ -100,6 +99,83 @@ func (s *azureProvider) DeleteSecret(key string) {
Expect(err).ToNot(HaveOccurred())
}
func (s *azureProvider) CreateKey(key string) *keyvault.JSONWebKey {
out, err := s.client.CreateKey(
context.Background(),
s.vaultURL,
key,
keyvault.KeyCreateParameters{
Kty: keyvault.RSA,
KeyAttributes: &keyvault.KeyAttributes{
RecoveryLevel: keyvault.Purgeable,
Enabled: utilpointer.BoolPtr(true),
},
},
)
Expect(err).ToNot(HaveOccurred())
return out.Key
}
func (s *azureProvider) DeleteKey(key string) {
_, err := s.client.DeleteKey(context.Background(), s.vaultURL, key)
Expect(err).ToNot(HaveOccurred())
}
func (s *azureProvider) CreateCertificate(key string) {
_, err := s.client.CreateCertificate(
context.Background(),
s.vaultURL,
key,
keyvault.CertificateCreateParameters{
CertificatePolicy: &keyvault.CertificatePolicy{
X509CertificateProperties: &keyvault.X509CertificateProperties{
Subject: utilpointer.String("CN=e2e.test"),
ValidityInMonths: utilpointer.Int32(42),
},
IssuerParameters: &keyvault.IssuerParameters{
Name: utilpointer.String("Self"),
},
Attributes: &keyvault.CertificateAttributes{
RecoveryLevel: keyvault.Purgeable,
Enabled: utilpointer.BoolPtr(true),
},
},
CertificateAttributes: &keyvault.CertificateAttributes{
RecoveryLevel: keyvault.Purgeable,
Enabled: utilpointer.BoolPtr(true),
},
},
)
Expect(err).ToNot(HaveOccurred())
}
func (s *azureProvider) GetCertificate(key string) []byte {
attempts := 20
for {
out, err := s.client.GetCertificate(
context.Background(),
s.vaultURL,
key,
"",
)
Expect(err).ToNot(HaveOccurred())
if out.Cer != nil {
return *out.Cer
}
attempts--
if attempts <= 0 {
Fail("failed fetching azkv certificate")
}
<-time.After(time.Second * 5)
}
}
func (s *azureProvider) DeleteCertificate(key string) {
_, err := s.client.DeleteCertificate(context.Background(), s.vaultURL, key)
Expect(err).ToNot(HaveOccurred())
}
func (s *azureProvider) CreateSecretStore() {
azureCreds := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{

View file

@ -16,7 +16,8 @@ package suite
import (
// import different e2e test suites.
_ "github.com/external-secrets/external-secrets/e2e/suite/aws"
_ "github.com/external-secrets/external-secrets/e2e/suite/aws/parameterstore"
_ "github.com/external-secrets/external-secrets/e2e/suite/aws/secretsmanager"
_ "github.com/external-secrets/external-secrets/e2e/suite/azure"
_ "github.com/external-secrets/external-secrets/e2e/suite/gcp"
_ "github.com/external-secrets/external-secrets/e2e/suite/vault"

29
go.mod
View file

@ -33,7 +33,7 @@ replace (
)
require (
cloud.google.com/go v0.99.0
cloud.google.com/go v0.100.2 // indirect
cloud.google.com/go/secretmanager v1.0.0
github.com/Azure/azure-sdk-for-go v61.1.0+incompatible
github.com/Azure/go-autorest/autorest/azure/auth v0.5.7
@ -45,33 +45,33 @@ require (
github.com/PaesslerAG/jsonpath v0.1.1
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0
github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2
github.com/akeylesslabs/akeyless-go/v2 v2.15.24
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1458
github.com/akeylesslabs/akeyless-go/v2 v2.15.25
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1473
github.com/aws/aws-sdk-go v1.38.6
github.com/crossplane/crossplane-runtime v0.15.1
github.com/go-logr/logr v1.2.2
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/google/go-cmp v0.5.7
github.com/google/uuid v1.2.0
github.com/googleapis/gax-go v1.0.3
github.com/googleapis/gax-go/v2 v2.1.1
github.com/hashicorp/vault/api v1.3.1
github.com/huandu/xstrings v1.3.2 // indirect
github.com/lestrrat-go/jwx v1.2.1
github.com/onsi/ginkgo/v2 v2.0.0
github.com/onsi/ginkgo/v2 v2.1.1
github.com/onsi/gomega v1.17.0
github.com/oracle/oci-go-sdk/v45 v45.2.0
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/client_model v0.2.0
github.com/stretchr/testify v1.7.0
github.com/tidwall/gjson v1.12.1
github.com/xanzy/go-gitlab v0.50.1
github.com/xanzy/go-gitlab v0.54.3
github.com/yandex-cloud/go-genproto v0.0.0-20210809082946-a97da516c588
github.com/yandex-cloud/go-sdk v0.0.0-20210809100642-c13c40a429fa
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
go.uber.org/zap v1.20.0
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
google.golang.org/api v0.61.0
google.golang.org/api v0.64.0
google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5
google.golang.org/grpc v1.43.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
@ -85,7 +85,10 @@ require (
software.sslmate.com/src/go-pkcs12 v0.0.0-20210415151418-c5206de65a78
)
require cloud.google.com/go/iam v0.1.1
require (
cloud.google.com/go/compute v0.1.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
@ -95,7 +98,6 @@ require (
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/PaesslerAG/gval v1.0.0 // indirect
github.com/armon/go-metrics v0.3.10 // indirect
github.com/armon/go-radix v1.0.0 // indirect
@ -103,16 +105,11 @@ require (
github.com/aws/aws-sdk-go-v2 v0.23.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 // indirect
github.com/envoyproxy/protoc-gen-validate v0.1.0 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
@ -131,10 +128,9 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@ -194,8 +190,6 @@ require (
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
@ -212,7 +206,6 @@ require (
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
honnef.co/go/tools v0.1.4 // indirect
k8s.io/apiextensions-apiserver v0.23.0 // indirect
k8s.io/component-base v0.23.0 // indirect
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c // indirect

59
go.sum
View file

@ -25,17 +25,23 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v0.1.0 h1:rSUBvAyVwNJ5uQCKNJFMwPtTvJkfN38b6Pvb9zZoqJ8=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/iam v0.1.1 h1:4CapQyNFjiksks1/x7jsvsygFPhihslYk5GptIrlX68=
cloud.google.com/go/iam v0.1.1/go.mod h1:CKqrcnI/suGpybEHxZ7BMehL0oA4LpdyJdUlTl9jVMw=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -78,7 +84,6 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
@ -107,15 +112,15 @@ github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 h1:+XfOU14S4bGuwyvCijJwhhBIj
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2 h1:1h4udX3Y5KgSG0m4Th2bHfaYxZB9fbngiij9PrKEp6c=
github.com/akeylesslabs/akeyless-go-cloud-id v0.3.2/go.mod h1:ionnWiARf5TYoFGuHS7syh51/7lYosZejpZbnECFJcU=
github.com/akeylesslabs/akeyless-go/v2 v2.15.24 h1:q++f8n4l66kSptlo9cxrYq8fGHg25GdjqOsw0vbKUAE=
github.com/akeylesslabs/akeyless-go/v2 v2.15.24/go.mod h1:uOdXD49NCCe4rexeSc2aBU5Qv4KZgJE6YlbtYalvb+I=
github.com/akeylesslabs/akeyless-go/v2 v2.15.25 h1:9iztd2fXVfj4b3LRsyvGNRheFoz8IFs/+K4GaAshZc4=
github.com/akeylesslabs/akeyless-go/v2 v2.15.25/go.mod h1:uOdXD49NCCe4rexeSc2aBU5Qv4KZgJE6YlbtYalvb+I=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1458 h1:pMdm+s6k9yeAYJNqgZIpZcDBuh2SNR3Q137G9rpxDZc=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1458/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1473 h1:rUoiu7Duq0hr4mjlQWZMORKaCbNXaYvYN2HFJQt228E=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1473/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@ -152,7 +157,6 @@ github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9cop
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@ -170,12 +174,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 h1:hzAQntlaYRkVSFEfj9OTWlVV1H155FMD8BTKktLv0QI=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1 h1:zH8ljVhhq7yC0MIeUL/IviMtY8hx2mK8cN9wEYb8ggw=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
@ -222,9 +224,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021 h1:fP+fF0up6oPY49OrjPrhIJ8yQfdIM85NXMLkMg1EXVs=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@ -340,7 +340,6 @@ github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@ -391,8 +390,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@ -422,9 +421,6 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go v1.0.3 h1:9dMLqhaibYONnDRcnHdUs9P8Mw64jLlZTYlDe3leBtQ=
github.com/googleapis/gax-go v1.0.3/go.mod h1:QyXYajJFdARxGzjwUfbDFIse7Spkw81SJ4LrBJXtlQ8=
github.com/googleapis/gax-go/v2 v2.0.2/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
@ -682,8 +678,8 @@ github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.1 h1:LCnPB85AvFNr91s0B2aDzEiiIg6MUwLYbryC1NSlWi8=
github.com/onsi/ginkgo/v2 v2.1.1/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
@ -814,8 +810,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/xanzy/go-gitlab v0.50.1 h1:eH1G0/ZV1j81rhGrtbcePjbM5Ern7mPA4Xjt+yE+2PQ=
github.com/xanzy/go-gitlab v0.50.1/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
github.com/xanzy/go-gitlab v0.54.3 h1:fPfZ3Jcu5dPc3xyIYtAALZsEgoyKNFNuULD+TdJ7Zvk=
github.com/xanzy/go-gitlab v0.54.3/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
@ -904,7 +900,6 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190221220918-438050ddec5e/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
@ -914,11 +909,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -930,7 +922,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@ -1109,6 +1100,8 @@ golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -1135,7 +1128,6 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -1243,8 +1235,10 @@ google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0 h1:TXXKS1slM3b2bZNJwD5DV/Tp6/M2cLzLOLh9PjDhrw8=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/api v0.64.0 h1:l3pi8ncrQgB9+ncFw3A716L8lWujnXniBYbxWqqy6tE=
google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1319,10 +1313,13 @@ google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 h1:zzNejm+EgrbLfDZ6lu9Uud2IVvHySPl8vQzf04laR5Q=
google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -1348,6 +1345,7 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
@ -1413,7 +1411,6 @@ gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919 h1:tmXTu+dfa+d9Evp8NpJdgOy6+rt8/x4yG7qPBrtNfLY=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -1421,8 +1418,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.4 h1:SadWOkti5uVN1FAMgxn165+Mw00fuQKyk4Gyn/inxNQ=
honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
k8s.io/api v0.23.0 h1:WrL1gb73VSC8obi8cuYETJGXEoFNEh3LU0Pt+Sokgro=
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
k8s.io/apiextensions-apiserver v0.23.0 h1:uii8BYmHYiT2ZTAJxmvc3X8UhNYMxl2A0z0Xq3Pm+WY=

View file

@ -61,6 +61,7 @@ nav:
- Oracle:
- Oracle Vault: provider-oracle-vault.md
- Webhook: provider-webhook.md
- Fake: provider-fake.md
- References:
- API specification: spec.md
- Contributing:

View file

@ -64,9 +64,7 @@ func (r *Reconciler) applyTemplate(ctx context.Context, es *esv1alpha1.ExternalS
// if no data was provided by template fallback
// to value from the provider
if len(es.Spec.Target.Template.Data) == 0 {
for k, v := range dataMap {
secret.Data[k] = v
}
secret.Data = dataMap
}
secret.Annotations[esv1alpha1.AnnotationDataHash] = utils.ObjectHash(secret.Data)

View file

@ -31,8 +31,8 @@ import (
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
"github.com/external-secrets/external-secrets/pkg/provider"
"github.com/external-secrets/external-secrets/pkg/provider/fake"
"github.com/external-secrets/external-secrets/pkg/provider/schema"
"github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
)
var (
@ -654,6 +654,85 @@ var _ = Describe("ExternalSecret controller", func() {
}
}
// when a provider secret was deleted it must be deleted from
// the secret aswell
refreshSecretValueMap := func(tc *testCase) {
fakeProvider.WithGetSecretMap(map[string][]byte{
"foo": []byte("1111"),
"bar": []byte("2222"),
}, nil)
tc.externalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{}
tc.externalSecret.Spec.DataFrom = []esv1alpha1.ExternalSecretDataRemoteRef{
{
Key: remoteKey,
},
}
tc.externalSecret.Spec.RefreshInterval = &metav1.Duration{Duration: time.Second}
tc.checkSecret = func(es *esv1alpha1.ExternalSecret, secret *v1.Secret) {
// check values
Expect(string(secret.Data["foo"])).To(Equal("1111"))
Expect(string(secret.Data["bar"])).To(Equal("2222"))
// update provider secret
sec := &v1.Secret{}
fakeProvider.WithGetSecretMap(map[string][]byte{
"foo": []byte("1111"),
}, nil)
secretLookupKey := types.NamespacedName{
Name: ExternalSecretTargetSecretName,
Namespace: ExternalSecretNamespace,
}
Eventually(func() bool {
err := k8sClient.Get(context.Background(), secretLookupKey, sec)
if err != nil {
return false
}
return string(sec.Data["foo"]) == "1111" &&
sec.Data["bar"] == nil // must not be defined, it was deleted
}, timeout, interval).Should(BeTrue())
}
}
// when a provider secret was deleted it must be deleted from
// the secret aswell when using a template
refreshSecretValueMapTemplate := func(tc *testCase) {
fakeProvider.WithGetSecretMap(map[string][]byte{
"foo": []byte("1111"),
"bar": []byte("2222"),
}, nil)
tc.externalSecret.Spec.Target.Template = &esv1alpha1.ExternalSecretTemplate{}
tc.externalSecret.Spec.Data = []esv1alpha1.ExternalSecretData{}
tc.externalSecret.Spec.DataFrom = []esv1alpha1.ExternalSecretDataRemoteRef{
{
Key: remoteKey,
},
}
tc.externalSecret.Spec.RefreshInterval = &metav1.Duration{Duration: time.Second}
tc.checkSecret = func(es *esv1alpha1.ExternalSecret, secret *v1.Secret) {
// check values
Expect(string(secret.Data["foo"])).To(Equal("1111"))
Expect(string(secret.Data["bar"])).To(Equal("2222"))
// update provider secret
sec := &v1.Secret{}
fakeProvider.WithGetSecretMap(map[string][]byte{
"foo": []byte("1111"),
}, nil)
secretLookupKey := types.NamespacedName{
Name: ExternalSecretTargetSecretName,
Namespace: ExternalSecretNamespace,
}
Eventually(func() bool {
err := k8sClient.Get(context.Background(), secretLookupKey, sec)
if err != nil {
return false
}
return string(sec.Data["foo"]) == "1111" &&
sec.Data["bar"] == nil // must not be defined, it was deleted
}, timeout, interval).Should(BeTrue())
}
}
refreshintervalZero := func(tc *testCase) {
const targetProp = "targetProperty"
const secretVal = "someValue"
@ -971,6 +1050,8 @@ var _ = Describe("ExternalSecret controller", func() {
Entry("should refresh secret from template", refreshWithTemplate),
Entry("should be able to use only metadata from template", onlyMetadataFromTemplate),
Entry("should refresh secret value when provider secret changes", refreshSecretValue),
Entry("should refresh secret map when provider secret changes", refreshSecretValueMap),
Entry("should refresh secret map when provider secret changes when using a template", refreshSecretValueMapTemplate),
Entry("should not refresh secret value when provider secret changes but refreshInterval is zero", refreshintervalZero),
Entry("should fetch secret using dataFrom", syncWithDataFrom),
Entry("should fetch secret using dataFrom and a template", syncWithDataFromTemplate),

View file

@ -16,6 +16,7 @@ package externalsecret
import (
"github.com/prometheus/client_golang/prometheus"
v1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/metrics"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
@ -50,6 +51,62 @@ var (
// updateExternalSecretCondition updates the ExternalSecret conditions.
func updateExternalSecretCondition(es *esv1alpha1.ExternalSecret, condition *esv1alpha1.ExternalSecretStatusCondition, value float64) {
switch condition.Type {
case esv1alpha1.ExternalSecretDeleted:
// Remove condition=Ready metrics when the object gets deleted.
externalSecretCondition.Delete(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(esv1alpha1.ExternalSecretReady),
"status": string(v1.ConditionFalse),
})
externalSecretCondition.Delete(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(esv1alpha1.ExternalSecretReady),
"status": string(v1.ConditionTrue),
})
case esv1alpha1.ExternalSecretReady:
// Remove condition=Deleted metrics when the object gets ready.
externalSecretCondition.Delete(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(esv1alpha1.ExternalSecretDeleted),
"status": string(v1.ConditionFalse),
})
externalSecretCondition.Delete(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(esv1alpha1.ExternalSecretDeleted),
"status": string(v1.ConditionTrue),
})
// Toggle opposite Status to 0
switch condition.Status {
case v1.ConditionFalse:
externalSecretCondition.With(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(esv1alpha1.ExternalSecretReady),
"status": string(v1.ConditionTrue),
}).Set(0)
case v1.ConditionTrue:
externalSecretCondition.With(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,
"condition": string(esv1alpha1.ExternalSecretReady),
"status": string(v1.ConditionFalse),
}).Set(0)
case v1.ConditionUnknown:
break
default:
break
}
default:
break
}
externalSecretCondition.With(prometheus.Labels{
"name": es.Name,
"namespace": es.Namespace,

View file

@ -15,6 +15,7 @@ limitations under the License.
package externalsecret
import (
"context"
"path/filepath"
"testing"
"time"
@ -40,6 +41,7 @@ import (
var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
var cancel context.CancelFunc
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
@ -56,6 +58,9 @@ var _ = BeforeSuite(func() {
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "deploy", "crds")},
}
var ctx context.Context
ctx, cancel = context.WithCancel(context.Background())
var err error
cfg, err = testEnv.Start()
Expect(err).ToNot(HaveOccurred())
@ -87,12 +92,13 @@ var _ = BeforeSuite(func() {
go func() {
defer GinkgoRecover()
Expect(k8sManager.Start(ctrl.SetupSignalHandler())).ToNot(HaveOccurred())
Expect(k8sManager.Start(ctx)).ToNot(HaveOccurred())
}()
})
var _ = AfterSuite(func() {
By("tearing down the test environment")
cancel() // stop manager
err := testEnv.Stop()
Expect(err).ToNot(HaveOccurred())
})

View file

@ -16,6 +16,7 @@ package fake
import (
"context"
"fmt"
"sigs.k8s.io/controller-runtime/pkg/client"
@ -24,80 +25,72 @@ import (
"github.com/external-secrets/external-secrets/pkg/provider/schema"
)
var _ provider.Provider = &Client{}
var (
errNotFound = fmt.Errorf("secret value not found")
errMissingStore = fmt.Errorf("missing store provider")
errMissingFakeProvider = fmt.Errorf("missing store provider fake")
)
// Client is a fake client for testing.
type Client struct {
NewFn func(context.Context, esv1alpha1.GenericStore, client.Client,
string) (provider.SecretsClient, error)
GetSecretFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error)
GetSecretMapFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
type Provider struct {
config *esv1alpha1.FakeProvider
}
// New returns a fake provider/client.
func New() *Client {
v := &Client{
GetSecretFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
return nil, nil
},
GetSecretMapFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
return nil, nil
},
}
v.NewFn = func(context.Context, esv1alpha1.GenericStore, client.Client, string) (provider.SecretsClient, error) {
return v, nil
}
return v
}
// RegisterAs registers the fake client in the schema.
func (v *Client) RegisterAs(provider *esv1alpha1.SecretStoreProvider) {
schema.ForceRegister(v, provider)
}
// GetSecret implements the provider.Provider interface.
func (v *Client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
return v.GetSecretFn(ctx, ref)
}
// WithGetSecret wraps secret data returned by this provider.
func (v *Client) WithGetSecret(secData []byte, err error) *Client {
v.GetSecretFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
return secData, err
}
return v
}
// GetSecretMap imeplements the provider.Provider interface.
func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
return v.GetSecretMapFn(ctx, ref)
}
func (v *Client) Close(ctx context.Context) error {
return nil
}
// WithGetSecretMap wraps the secret data map returned by this fake provider.
func (v *Client) WithGetSecretMap(secData map[string][]byte, err error) *Client {
v.GetSecretMapFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
return secData, err
}
return v
}
// WithNew wraps the fake provider factory function.
func (v *Client) WithNew(f func(context.Context, esv1alpha1.GenericStore, client.Client,
string) (provider.SecretsClient, error)) *Client {
v.NewFn = f
return v
}
// NewClient returns a new fake provider.
func (v *Client) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (provider.SecretsClient, error) {
c, err := v.NewFn(ctx, store, kube, namespace)
func (p *Provider) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (provider.SecretsClient, error) {
cfg, err := getProvider(store)
if err != nil {
return nil, err
}
return c, nil
return &Provider{
config: cfg,
}, nil
}
func getProvider(store esv1alpha1.GenericStore) (*esv1alpha1.FakeProvider, error) {
if store == nil {
return nil, errMissingStore
}
spc := store.GetSpec()
if spc == nil || spc.Provider == nil || spc.Provider.Fake == nil {
return nil, errMissingFakeProvider
}
return spc.Provider.Fake, nil
}
// GetSecret returns a single secret from the provider.
func (p *Provider) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
for _, data := range p.config.Data {
if data.Key == ref.Key && data.Version == ref.Version {
return []byte(data.Value), nil
}
}
return nil, errNotFound
}
// GetSecretMap returns multiple k/v pairs from the provider.
func (p *Provider) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
for _, data := range p.config.Data {
if data.Key != ref.Key || data.Version != ref.Version || data.ValueMap == nil {
continue
}
return convertMap(data.ValueMap), nil
}
return nil, errNotFound
}
func convertMap(in map[string]string) map[string][]byte {
m := make(map[string][]byte)
for k, v := range in {
m[k] = []byte(v)
}
return m
}
func (p *Provider) Close(ctx context.Context) error {
return nil
}
func init() {
schema.Register(&Provider{}, &esv1alpha1.SecretStoreProvider{
Fake: &esv1alpha1.FakeProvider{},
})
}

View file

@ -0,0 +1,194 @@
/*
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 fake
import (
"context"
"testing"
"github.com/onsi/gomega"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
)
func TestNewClient(t *testing.T) {
p := &Provider{}
gomega.RegisterTestingT(t)
// nil store
_, err := p.NewClient(context.Background(), nil, nil, "")
gomega.Expect(err).To(gomega.HaveOccurred())
// missing provider
_, err = p.NewClient(context.Background(), &esv1alpha1.SecretStore{}, nil, "")
gomega.Expect(err).To(gomega.HaveOccurred())
}
func TestClose(t *testing.T) {
p := &Provider{}
gomega.RegisterTestingT(t)
err := p.Close(context.TODO())
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
type testCase struct {
name string
input []esv1alpha1.FakeProviderData
request esv1alpha1.ExternalSecretDataRemoteRef
expValue string
expErr string
}
func TestGetSecret(t *testing.T) {
gomega.RegisterTestingT(t)
p := &Provider{}
tbl := []testCase{
{
name: "return err when not found",
input: []esv1alpha1.FakeProviderData{},
request: esv1alpha1.ExternalSecretDataRemoteRef{
Key: "/foo",
Version: "v2",
},
expErr: "secret value not found",
},
{
name: "get correct value from multiple versions",
input: []esv1alpha1.FakeProviderData{
{
Key: "/foo",
Value: "bar2",
Version: "v2",
},
{
Key: "junk",
Value: "xxxxx",
},
{
Key: "/foo",
Value: "bar1",
Version: "v1",
},
},
request: esv1alpha1.ExternalSecretDataRemoteRef{
Key: "/foo",
Version: "v2",
},
expValue: "bar2",
},
}
for _, row := range tbl {
t.Run(row.name, func(t *testing.T) {
cl, err := p.NewClient(context.Background(), &esv1alpha1.SecretStore{
Spec: esv1alpha1.SecretStoreSpec{
Provider: &esv1alpha1.SecretStoreProvider{
Fake: &esv1alpha1.FakeProvider{
Data: row.input,
},
},
},
}, nil, "")
gomega.Expect(err).ToNot(gomega.HaveOccurred())
out, err := cl.GetSecret(context.Background(), row.request)
if row.expErr != "" {
gomega.Expect(err).To(gomega.MatchError(row.expErr))
} else {
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
gomega.Expect(string(out)).To(gomega.Equal(row.expValue))
})
}
}
type testMapCase struct {
name string
input []esv1alpha1.FakeProviderData
request esv1alpha1.ExternalSecretDataRemoteRef
expValue map[string][]byte
expErr string
}
func TestGetSecretMap(t *testing.T) {
gomega.RegisterTestingT(t)
p := &Provider{}
tbl := []testMapCase{
{
name: "return err when not found",
input: []esv1alpha1.FakeProviderData{},
request: esv1alpha1.ExternalSecretDataRemoteRef{
Key: "/foo",
Version: "v2",
},
expErr: "secret value not found",
},
{
name: "get correct value from multiple versions",
input: []esv1alpha1.FakeProviderData{
{
Key: "junk",
ValueMap: map[string]string{
"junk": "ok",
},
},
{
Key: "/foo",
ValueMap: map[string]string{
"foo": "bar",
"baz": "bang",
},
Version: "v1",
},
{
Key: "/foo",
ValueMap: map[string]string{
"foo": "bar",
"baz": "bang",
},
Version: "v2",
},
},
request: esv1alpha1.ExternalSecretDataRemoteRef{
Key: "/foo",
Version: "v2",
},
expValue: map[string][]byte{
"foo": []byte("bar"),
"baz": []byte("bang"),
},
},
}
for _, row := range tbl {
t.Run(row.name, func(t *testing.T) {
cl, err := p.NewClient(context.Background(), &esv1alpha1.SecretStore{
Spec: esv1alpha1.SecretStoreSpec{
Provider: &esv1alpha1.SecretStoreProvider{
Fake: &esv1alpha1.FakeProvider{
Data: row.input,
},
},
},
}, nil, "")
gomega.Expect(err).ToNot(gomega.HaveOccurred())
out, err := cl.GetSecretMap(context.Background(), row.request)
if row.expErr != "" {
gomega.Expect(err).To(gomega.MatchError(row.expErr))
} else {
gomega.Expect(err).ToNot(gomega.HaveOccurred())
}
gomega.Expect(out).To(gomega.Equal(row.expValue))
})
}
}

View file

@ -19,7 +19,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
grpc "github.com/googleapis/gax-go"
grpc "github.com/googleapis/gax-go/v2"
secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
)

View file

@ -19,7 +19,7 @@ import (
"fmt"
secretmanager "cloud.google.com/go/secretmanager/apiv1"
"github.com/googleapis/gax-go"
"github.com/googleapis/gax-go/v2"
"github.com/tidwall/gjson"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"

View file

@ -24,7 +24,7 @@ import (
iam "cloud.google.com/go/iam/credentials/apiv1"
secretmanager "cloud.google.com/go/secretmanager/apiv1"
"github.com/googleapis/gax-go"
"github.com/googleapis/gax-go/v2"
"golang.org/x/oauth2"
"google.golang.org/api/option"
credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"

View file

@ -21,7 +21,7 @@ import (
"net/http/httptest"
"testing"
"github.com/googleapis/gax-go"
"github.com/googleapis/gax-go/v2"
"github.com/stretchr/testify/assert"
"golang.org/x/oauth2"
credentialspb "google.golang.org/genproto/googleapis/iam/credentials/v1"

View file

@ -21,6 +21,7 @@ import (
_ "github.com/external-secrets/external-secrets/pkg/provider/alibaba"
_ "github.com/external-secrets/external-secrets/pkg/provider/aws"
_ "github.com/external-secrets/external-secrets/pkg/provider/azure/keyvault"
_ "github.com/external-secrets/external-secrets/pkg/provider/fake"
_ "github.com/external-secrets/external-secrets/pkg/provider/gcp/secretmanager"
_ "github.com/external-secrets/external-secrets/pkg/provider/gitlab"
_ "github.com/external-secrets/external-secrets/pkg/provider/ibm"

View file

@ -0,0 +1,103 @@
/*
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 fake
import (
"context"
"sigs.k8s.io/controller-runtime/pkg/client"
esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
"github.com/external-secrets/external-secrets/pkg/provider"
"github.com/external-secrets/external-secrets/pkg/provider/schema"
)
var _ provider.Provider = &Client{}
// Client is a fake client for testing.
type Client struct {
NewFn func(context.Context, esv1alpha1.GenericStore, client.Client,
string) (provider.SecretsClient, error)
GetSecretFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error)
GetSecretMapFn func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error)
}
// New returns a fake provider/client.
func New() *Client {
v := &Client{
GetSecretFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
return nil, nil
},
GetSecretMapFn: func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
return nil, nil
},
}
v.NewFn = func(context.Context, esv1alpha1.GenericStore, client.Client, string) (provider.SecretsClient, error) {
return v, nil
}
return v
}
// RegisterAs registers the fake client in the schema.
func (v *Client) RegisterAs(provider *esv1alpha1.SecretStoreProvider) {
schema.ForceRegister(v, provider)
}
// GetSecret implements the provider.Provider interface.
func (v *Client) GetSecret(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
return v.GetSecretFn(ctx, ref)
}
// WithGetSecret wraps secret data returned by this provider.
func (v *Client) WithGetSecret(secData []byte, err error) *Client {
v.GetSecretFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) ([]byte, error) {
return secData, err
}
return v
}
// GetSecretMap imeplements the provider.Provider interface.
func (v *Client) GetSecretMap(ctx context.Context, ref esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
return v.GetSecretMapFn(ctx, ref)
}
func (v *Client) Close(ctx context.Context) error {
return nil
}
// WithGetSecretMap wraps the secret data map returned by this fake provider.
func (v *Client) WithGetSecretMap(secData map[string][]byte, err error) *Client {
v.GetSecretMapFn = func(context.Context, esv1alpha1.ExternalSecretDataRemoteRef) (map[string][]byte, error) {
return secData, err
}
return v
}
// WithNew wraps the fake provider factory function.
func (v *Client) WithNew(f func(context.Context, esv1alpha1.GenericStore, client.Client,
string) (provider.SecretsClient, error)) *Client {
v.NewFn = f
return v
}
// NewClient returns a new fake provider.
func (v *Client) NewClient(ctx context.Context, store esv1alpha1.GenericStore, kube client.Client, namespace string) (provider.SecretsClient, error) {
c, err := v.NewFn(ctx, store, kube, namespace)
if err != nil {
return nil, err
}
return c, nil
}

View file

@ -298,7 +298,9 @@ func testGetSecret(tc testCase, t *testing.T, client provider.SecretsClient) {
Key: tc.Args.Key,
Version: tc.Args.Version,
}
secret, err := client.GetSecret(context.Background(), testRef)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
secret, err := client.GetSecret(ctx, testRef)
errStr := ""
if err != nil {
errStr = err.Error()

View file

@ -37,6 +37,25 @@ resource "aws_iam_role" "eso-e2e-irsa" {
"arn:aws:iam::aws:policy/SecretsManagerReadWrite"
]
inline_policy {
name = "aws_ssm_parameterstore"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ssm:GetParameter",
"ssm:PutParameter",
]
Effect = "Allow"
Resource = "*"
},
]
})
}
}
resource "null_resource" "apply_sa" {