Skip to content
This repository was archived by the owner on Jul 26, 2022. It is now read-only.

Commit 131e201

Browse files
authored
feat: Chart optionally installs CRD / CR Manager configurable for more strict clusters (#344)
Coupling the CRD creation to a controller requires an unnecessarily privileged cluster role. In some clusters, admins would not be willing to grant the controller service account that role. We require the chart itself to install the CRD, and the service account or admin installing the chart would have the crd:create access while the controller be more tightly scoped. This essentially deprecates the custom resource manager so that it can removed entirely in future 4.x releases.
1 parent cceb40b commit 131e201

15 files changed

+208
-47
lines changed

.dockerignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
.env
22
architecture.png
3-
charts
3+
charts/**/.helmignore
4+
charts/**/Chart.yaml
5+
charts/**/README.md
6+
charts/**/templates/
7+
charts/**/values.yaml
48
coverage
59
Dockerfile
610
node_modules

.github/workflows/workflow.yml

+13-1
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,23 @@ jobs:
1717
test-e2e:
1818
runs-on: ubuntu-latest
1919
name: E2E
20+
strategy:
21+
matrix:
22+
disableCustomResourceManager: ['true', 'false']
23+
helmVersion: ['V2', 'V3']
2024
steps:
2125
- uses: actions/checkout@v2
2226
- name: Setup node
2327
uses: actions/setup-node@v1
2428
with:
2529
node-version: 12
30+
- uses: azure/setup-helm@v1
31+
with:
32+
version: v2.16.1
33+
if: matrix.helmVersion == 'V2'
34+
- name: configure helm v2
35+
run: |
36+
helm init --client-only
37+
if: matrix.helmVersion == 'V2'
2638
- run: npm install
27-
- run: npm run test-e2e
39+
- run: npm run test-e2e -- ${{ matrix.disableCustomResourceManager }} ${{ matrix.helmVersion }}

bin/daemon.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ async function main () {
3131
logger.info('loading kube specs')
3232
await kubeClient.loadSpec()
3333
logger.info('successfully loaded kube specs')
34-
logger.info('updating CRD')
35-
await customResourceManager.upsertResource({ customResourceManifest })
36-
logger.info('successfully updated CRD')
34+
await customResourceManager.manageCrd({ customResourceManifest })
3735

3836
const externalSecretEvents = getExternalSecretEvents({
3937
kubeClient,

charts/kubernetes-external-secrets/README.md

+40-9
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44

55
## TL;DR;
66

7+
Assumes you are using Helm V3:
8+
79
```bash
810
$ helm repo add external-secrets https://godaddy.github.io/kubernetes-external-secrets/
9-
$ helm install external-secrets/kubernetes-external-secrets
11+
$ helm install kubernetes-external-secrets external-secrets/kubernetes-external-secrets --skip-crds
1012
```
1113

14+
See below for [Helm V2 considerations](#helm-v2-considerations) when installing the chart.
15+
1216
## Prerequisites
1317

1418
* Kubernetes 1.12+
@@ -18,15 +22,39 @@ $ helm install external-secrets/kubernetes-external-secrets
1822
To install the chart with the release named `my-release`:
1923

2024
```bash
21-
$ helm install --name my-release external-secrets/kubernetes-external-secrets
25+
$ helm install my-release external-secrets/kubernetes-external-secrets --skip-crds
2226
```
2327

24-
> **Tip:** A namespace can be specified by the `Helm` option '`--namespace kube-external-secrets`'
28+
> **Tip:** A namespace can be specified by the `Helm` option '`--namespace kube-external-secrets`', however know this will not [autocreate a namespace](https://helm.sh/docs/faq/#automatically-creating-namespaces) like in Helm V2. To do that, also add the `--create-namespace` flag.
29+
30+
> **Note**: `--skip-crds` is required in order to ensure the custom resource manager is used and will work for backwards compatibility. In future 4.x releases, this will not be required. See below for how to [disable the custom resource manager](#installing-the-crd) via the chart.
2531
2632
To install the chart with [AWS IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html):
2733

2834
```bash
29-
$ helm install --name my-release --set securityContext.fsGroup=65534 --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"='arn:aws:iam::111111111111:role/ROLENAME' external-secrets/kubernetes-external-secrets
35+
$ helm install my-release external-secrets/kubernetes-external-secrets --skip-crds --set securityContext.fsGroup=65534 --set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"='arn:aws:iam::111111111111:role/ROLENAME'
36+
```
37+
38+
### Installing the CRD
39+
40+
To install the `ExternalSecret` CRD via the chart and disable the custom resource manager, you can omit `--skip-crds` and set `customResourceManagerDisabled`:
41+
42+
```bash
43+
$ helm install external-secrets/kubernetes-external-secrets --name my-release --set customResourceManagerDisabled=true
44+
```
45+
46+
### Helm V2 Considerations
47+
48+
For Helm V2, `--skip-crds` is not needed, but `--name` is in order to set the release name:
49+
50+
```bash
51+
$ helm install external-secrets/kubernetes-external-secrets --name my-release
52+
```
53+
54+
If you wish to disable the custom resource manager and install the CRD via Helm V2, then `crds.create` must also be set:
55+
56+
```bash
57+
$ helm install external-secrets/kubernetes-external-secrets --name my-release --set customResourceManagerDisabled=true --set crds.create=true
3058
```
3159

3260
## Uninstalling the Chart
@@ -43,6 +71,8 @@ The following table lists the configurable parameters of the `kubernetes-externa
4371

4472
| Parameter | Description | Default |
4573
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
74+
| `crds.create` | For Helm V2 installations of the chart to install the CRD, for V3 installations use `--skip-crds` appropriately | `false` |
75+
| `customResourceManagedDisabled` | Disables the custom resource manager, requiring the CRD be installed via the chart or other means | `false` |
4676
| `env.AWS_REGION` | Set AWS_REGION in Deployment Pod | `us-west-2` |
4777
| `env.LOG_LEVEL` | Set the application log level | `info` |
4878
| `env.METRICS_PORT` | Specify the port for the prometheus metrics server | `3001` |
@@ -55,9 +85,9 @@ The following table lists the configurable parameters of the `kubernetes-externa
5585
| `envVarsFromSecret.AZURE_TENANT_ID` | Set AZURE_TENANT_ID (from a secret) in Deployment Pod | |
5686
| `envVarsFromSecret.AZURE_CLIENT_ID` | Set AZURE_CLIENT_ID (from a secret) in Deployment Pod | |
5787
| `envVarsFromSecret.AZURE_CLIENT_SECRET` | Set AZURE_CLIENT_SECRET (from a secret) in Deployment Pod | |
58-
| `envVarsFromSecret.ALICLOUD_ENDPOINT` | Set ALICLOUD_ENDPOINT for KMS Service in Deployment Pod | |
59-
| `envVarsFromSecret.ALICLOUD_ACCESS_KEY_ID` | Set ALICLOUD_ACCESS_KEY_ID (from a secret) in Deployment Pod | |
60-
| `envVarsFromSecret.ALICLOUD_ACCESS_KEY_SECRET` | Set ALICLOUD_ACCESS_KEY_SECRET (from a secret) in Deployment Pod | |
88+
| `envVarsFromSecret.ALICLOUD_ENDPOINT` | Set ALICLOUD_ENDPOINT for KMS Service in Deployment Pod | |
89+
| `envVarsFromSecret.ALICLOUD_ACCESS_KEY_ID` | Set ALICLOUD_ACCESS_KEY_ID (from a secret) in Deployment Pod | |
90+
| `envVarsFromSecret.ALICLOUD_ACCESS_KEY_SECRET` | Set ALICLOUD_ACCESS_KEY_SECRET (from a secret) in Deployment Pod | |
6191
| `image.repository` | kubernetes-external-secrets Image name | `godaddy/kubernetes-external-secrets` |
6292
| `image.tag` | kubernetes-external-secrets Image tag | `3.2.0` |
6393
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
@@ -83,15 +113,16 @@ The following table lists the configurable parameters of the `kubernetes-externa
83113
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
84114

85115
```bash
86-
helm install external-secrets/kubernetes-external-secrets --name my-releases \
116+
helm install my-release external-secrets/kubernetes-external-secrets \
117+
--set customResourceManagerDisabled=true
87118
--set env.POLLER_INTERVAL_MILLISECONDS='300000' \
88119
--set podAnnotations."iam\.amazonaws\.com/role"='Name-Of-IAM-Role-With-SecretManager-Access'
89120
```
90121

91122
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example,
92123

93124
```bash
94-
helm install external-secrets/kubernetes-external-secrets --name my-release -f values.yaml
125+
helm install my-release external-secrets/kubernetes-external-secrets -f values.yaml
95126
```
96127

97128
> **Tip**: You can use the default [values.yaml](https://github.com/godaddy/kubernetes-external-secrets/blob/master/charts/kubernetes-external-secrets/values.yaml)

crd.yaml charts/kubernetes-external-secrets/crds/kubernetes-client.io_externalsecrets_crd.yaml

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,35 @@
1+
---
12
apiVersion: apiextensions.k8s.io/v1beta1
23
kind: CustomResourceDefinition
34
metadata:
45
name: externalsecrets.kubernetes-client.io
6+
annotations:
7+
# for helm v2 backwards compatibility
8+
helm.sh/hook: crd-install
9+
# used in e2e testing
10+
app.kubernetes.io/managed-by: helm
511
spec:
612
group: kubernetes-client.io
713
version: v1
814
scope: Namespaced
915

1016
names:
1117
shortNames:
12-
- es
18+
- es
1319
kind: ExternalSecret
1420
plural: externalsecrets
1521
singular: externalsecret
1622

1723
additionalPrinterColumns:
18-
- JSONPath: .status.lastSync
19-
name: Last Sync
20-
type: date
21-
- JSONPath: .status.status
22-
name: status
23-
type: string
24-
- JSONPath: .metadata.creationTimestamp
25-
name: Age
26-
type: date
24+
- JSONPath: .status.lastSync
25+
name: Last Sync
26+
type: date
27+
- JSONPath: .status.status
28+
name: status
29+
type: string
30+
- JSONPath: .metadata.creationTimestamp
31+
name: Age
32+
type: date
2733

2834
validation:
2935
openAPIV3Schema:
@@ -110,9 +116,8 @@ spec:
110116
- alicloudSecretsManager
111117
anyOf:
112118
- required:
113-
- data
119+
- data
114120
- required:
115-
- dataFrom
116-
121+
- dataFrom
117122
subresources:
118123
status: {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{{- if .Values.customResourceManagerDisabled }}
2+
{{- if .Values.crds.create }}
3+
{{- range $path, $bytes := .Files.Glob "crds/*.yaml" }}
4+
{{ $.Files.Get $path }}
5+
---
6+
{{- end }}
7+
{{- end }}
8+
{{- end }}

charts/kubernetes-external-secrets/templates/deployment.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ spec:
4141
resources:
4242
{{- toYaml .Values.resources | nindent 12 }}
4343
env:
44+
{{- if .Values.customResourceManagerDisabled }}
45+
- name: DISABLE_CUSTOM_RESOURCE_MANAGER
46+
value: "true"
47+
{{- end }}
4448
{{- range $name, $value := .Values.env }}
4549
{{- if not (empty $value) }}
4650
- name: {{ $name | quote }}

charts/kubernetes-external-secrets/templates/rbac.yaml

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ rules:
1515
- apiGroups: [""]
1616
resources: ["namespaces"]
1717
verbs: ["get", "watch", "list"]
18-
- apiGroups: ["apiextensions.k8s.io"]
19-
resources: ["customresourcedefinitions"]
20-
verbs: ["create"]
2118
- apiGroups: ["apiextensions.k8s.io"]
2219
resources: ["customresourcedefinitions"]
2320
resourceNames: ["externalsecrets.kubernetes-client.io"]
@@ -28,6 +25,11 @@ rules:
2825
- apiGroups: ["kubernetes-client.io"]
2926
resources: ["externalsecrets/status"]
3027
verbs: ["get", "update"]
28+
{{- if .Values.customResourceManagerDisabled | not }}
29+
- apiGroups: ["apiextensions.k8s.io"]
30+
resources: ["customresourcedefinitions"]
31+
verbs: ["create"]
32+
{{- end }}
3133
---
3234
apiVersion: rbac.authorization.k8s.io/v1beta1
3335
kind: ClusterRoleBinding

charts/kubernetes-external-secrets/values.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22
# This is a YAML-formatted file.
33
# Declare variables to be passed into your templates.
44

5+
# Determines whether the Helm chart or kubernetes-external-secrets
6+
# will handle the ExternalSecret CRD
7+
customResourceManagerDisabled: false
8+
9+
crds:
10+
# only needed for helm v2, leave this disabled for helm v3
11+
create: false
12+
513
# Environment variables to set on deployment pod
614
env:
715
AWS_REGION: us-west-2
16+
AWS_DEFAULT_REGION: us-west-2
817
POLLER_INTERVAL_MILLISECONDS: 10000 # Caution, setting this frequency may incur additional charges on some platforms
918
LOG_LEVEL: info
1019
METRICS_PORT: 3001

config/environment.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const namingPermittedAnnotation = process.env.NAMING_PERMITTED_ANNOTATION || 'ex
2828

2929
const metricsPort = process.env.METRICS_PORT || 3001
3030

31+
const customResourceManagerDisabled = 'DISABLE_CUSTOM_RESOURCE_MANAGER' in process.env
32+
3133
module.exports = {
3234
vaultEndpoint,
3335
environment,
@@ -36,5 +38,6 @@ module.exports = {
3638
rolePermittedAnnotation,
3739
namingPermittedAnnotation,
3840
pollingDisabled,
39-
logLevel
41+
logLevel,
42+
customResourceManagerDisabled
4043
}

config/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const AliCloudSecretsManagerBackend = require('../lib/backends/alicloud-secrets-
2323

2424
// Get document, or throw exception on error
2525
// eslint-disable-next-line security/detect-non-literal-fs-filename
26-
const customResourceManifest = yaml.safeLoad(fs.readFileSync(path.resolve(__dirname, '../crd.yaml'), 'utf8'))
26+
const customResourceManifest = yaml.safeLoad(fs.readFileSync(path.resolve(__dirname, '../charts/kubernetes-external-secrets/crds/kubernetes-client.io_externalsecrets_crd.yaml'), 'utf8'))
27+
customResourceManifest.metadata.annotations['app.kubernetes.io/managed-by'] = 'custom-resource-manager'
2728

2829
const kubeconfig = new kube.KubeConfig()
2930
kubeconfig.loadFromDefault()
@@ -39,7 +40,8 @@ const logger = pino({
3940

4041
const customResourceManager = new CustomResourceManager({
4142
kubeClient,
42-
logger
43+
logger,
44+
disabled: envConfig.customResourceManagerDisabled
4345
})
4446

4547
const secretsManagerBackend = new SecretsManagerBackend({

e2e/run-e2e-suite.sh

+26-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
16+
17+
DISABLE_CUSTOM_RESOURCE_MANAGER=${1:-true}
18+
HELM_VERSION=${2:-V3}
19+
1620
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
1721
KIND_LOGGING="--quiet"
1822
if ! [ -z "$DEBUG" ]; then
@@ -66,7 +70,27 @@ trap cleanup EXIT
6670

6771
kubectl apply -f ${DIR}/localstack.deployment.yaml
6872

69-
helm template e2e $DIR/../charts/kubernetes-external-secrets \
73+
CHART_DIR="$(dirname "$DIR")/charts/kubernetes-external-secrets"
74+
HELM_TEMPLATE_ARGS="e2e ${CHART_DIR}"
75+
HELM_TEMPLATE_EXTRA_ARGS="--include-crds --set customResourceManagerDisabled=true"
76+
E2E_EXTRA_ARGS="--env=DISABLE_CUSTOM_RESOURCE_MANAGER=true"
77+
if [[ "$HELM_VERSION" == "V3" ]]; then
78+
if [[ "$DISABLE_CUSTOM_RESOURCE_MANAGER" == "false" ]]; then
79+
HELM_TEMPLATE_EXTRA_ARGS="--skip-crds"
80+
E2E_EXTRA_ARGS=""
81+
fi
82+
else
83+
HELM_TEMPLATE_ARGS="${CHART_DIR} --name e2e"
84+
if [[ "$DISABLE_CUSTOM_RESOURCE_MANAGER" == "true" ]]; then
85+
HELM_TEMPLATE_EXTRA_ARGS="--set crds.create=true --set customResourceManagerDisabled=true"
86+
else
87+
HELM_TEMPLATE_EXTRA_ARGS=""
88+
E2E_EXTRA_ARGS=""
89+
fi
90+
fi
91+
92+
helm template ${HELM_TEMPLATE_ARGS} \
93+
${HELM_TEMPLATE_EXTRA_ARGS} \
7094
--set image.repository=external-secrets \
7195
--set image.tag=test \
7296
--set env.LOG_LEVEL=debug \
@@ -94,7 +118,6 @@ until kubectl get secret | grep -q ^external-secrets-e2e-token; do \
94118
done
95119

96120
echo -e "${BGREEN}Starting external-secrets e2e tests...${NC}"
97-
98121
kubectl rollout status deploy/localstack
99122
kubectl rollout status deploy/e2e-kubernetes-external-secrets
100123

@@ -109,6 +132,7 @@ kubectl run \
109132
--env="AWS_DEFAULT_REGION=us-east-1" \
110133
--env="AWS_REGION=us-east-1" \
111134
--env="LOCALSTACK_STS_URL=http://sts" \
135+
${E2E_EXTRA_ARGS} \
112136
--generator=run-pod/v1 \
113137
--overrides='{ "apiVersion": "v1", "spec":{"serviceAccountName": "external-secrets-e2e"}}' \
114138
e2e --image=external-secrets-e2e:test

e2e/tests/crd.test.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,30 @@ const { expect } = require('chai')
55

66
const {
77
kubeClient,
8-
customResourceManifest
8+
customResourceManifest,
9+
customResourceManagerDisabled
910
} = require('../../config')
1011

1112
const {
1213
uuid
1314
} = require('./framework.js')
1415

1516
describe('CRD', () => {
16-
it('should register the CRD on startup', async () => {
17+
it('ensure CRD is managed correctly', async () => {
1718
const res = await kubeClient
1819
.apis['apiextensions.k8s.io']
1920
.v1beta1
2021
.customresourcedefinitions(customResourceManifest.metadata.name)
2122
.get()
23+
24+
let managedBy = 'custom-resource-manager'
25+
if (customResourceManagerDisabled) {
26+
managedBy = 'helm'
27+
}
28+
2229
expect(res).to.not.equal(undefined)
2330
expect(res.statusCode).to.equal(200)
31+
expect(res.body.metadata.annotations['app.kubernetes.io/managed-by']).to.equal(managedBy)
2432
})
2533

2634
it('should reject invalid ExternalSecret manifests', async () => {

0 commit comments

Comments
 (0)