Compare commits
	
		
			51 Commits
		
	
	
		
			Lerentis/i
			...
			e141888335
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e141888335 | ||
|  | d8dc1a2de9 | ||
| fb342b36fc | |||
|  | c290d6aeaf | ||
| 5b445ae668 | |||
| baed77e570 | |||
| 20527b348a | |||
| bb50495347 | |||
|  | 297fb37f13 | ||
|  | cd5ebde2ba | ||
|  | 38459629bc | ||
|  | f5b72a18ac | ||
|  | 1a08ada5e4 | ||
|  | e1c8f49c11 | ||
|  | 892dc90e99 | ||
|  | c0a4add3b0 | ||
|  | 09f978d9fe | ||
|  | f679aa1a2b | ||
| b01f410f9f | |||
| 1128051a5b | |||
| c9c36f1a37 | |||
|  | 1820bd06c3 | ||
|  | fac9c5ef80 | ||
|  | 858c85bf2b | ||
|  | ac8f6bc8e0 | ||
|  | b35670f0fb | ||
|  | 63728bbc3a | ||
|  | 8175280a48 | ||
|  | 907c72e111 | ||
|  | f33ae2839d | ||
| 1758234a1f | |||
| 30794c10b5 | |||
| e58b390c43 | |||
|  | b2c7cc5c36 | ||
|  | d0753c5c9c | ||
|  | d5689ebf6e | ||
|  | 9320d4dcd6 | ||
|  | 593526b8ac | ||
|  | 3ef467ed75 | ||
|  | fd1bf9caa2 | ||
| 2b75b919b2 | |||
| be8f21e9c4 | |||
| 69290f689d | |||
|  | aeedda8640 | ||
|  | cef07ff4c5 | ||
|  | 2bf13bc8c5 | ||
| 48754d4578 | |||
|  | a2186ab3aa | ||
| 9f4264d355 | |||
| 620d0f0b18 | |||
| ac0bc2d89d | 
							
								
								
									
										6
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @@ -24,7 +24,7 @@ jobs: | |||||||
|           git config user.email "$GITHUB_ACTOR@users.noreply.github.com" |           git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | ||||||
|  |  | ||||||
|       - name: Install Helm |       - name: Install Helm | ||||||
|         uses: azure/setup-helm@v3 |         uses: azure/setup-helm@v4 | ||||||
|         with: |         with: | ||||||
|           version: v3.10.0 |           version: v3.10.0 | ||||||
|  |  | ||||||
| @@ -36,7 +36,7 @@ jobs: | |||||||
|           CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" |           CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||||||
|  |  | ||||||
|       - name: Get app version from chart |       - name: Get app version from chart | ||||||
|         uses: mikefarah/yq@v4.40.5 |         uses: mikefarah/yq@v4.44.2 | ||||||
|         id: app_version |         id: app_version | ||||||
|         with: |         with: | ||||||
|           cmd: yq '.appVersion' charts/bitwarden-crd-operator/Chart.yaml |           cmd: yq '.appVersion' charts/bitwarden-crd-operator/Chart.yaml | ||||||
| @@ -56,7 +56,7 @@ jobs: | |||||||
|  |  | ||||||
|       - name: "GHCR Build and Push" |       - name: "GHCR Build and Push" | ||||||
|         id: docker_build |         id: docker_build | ||||||
|         uses: docker/build-push-action@v5 |         uses: docker/build-push-action@v6 | ||||||
|         with: |         with: | ||||||
|           push: true |           push: true | ||||||
|           platforms: linux/amd64,linux/arm64 |           platforms: linux/amd64,linux/arm64 | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								.github/workflows/test-and-lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/test-and-lint.yml
									
									
									
									
										vendored
									
									
								
							| @@ -12,7 +12,7 @@ jobs: | |||||||
|           fetch-depth: 0 |           fetch-depth: 0 | ||||||
|  |  | ||||||
|       - name: Set up Helm |       - name: Set up Helm | ||||||
|         uses: azure/setup-helm@v3 |         uses: azure/setup-helm@v4 | ||||||
|         with: |         with: | ||||||
|           version: v3.11.2 |           version: v3.11.2 | ||||||
|  |  | ||||||
| @@ -36,6 +36,18 @@ jobs: | |||||||
|         if: steps.list-changed.outputs.changed == 'true' |         if: steps.list-changed.outputs.changed == 'true' | ||||||
|         run: ct lint --target-branch ${{ github.event.repository.default_branch }} |         run: ct lint --target-branch ${{ github.event.repository.default_branch }} | ||||||
|  |  | ||||||
|  |       - name: Install ah cli | ||||||
|  |         run: | | ||||||
|  |           export AH_VERSION=1.17.0 | ||||||
|  |           curl -LO https://github.com/artifacthub/hub/releases/download/v${AH_VERSION}/ah_${AH_VERSION}_linux_amd64.tar.gz | ||||||
|  |           tar -xf ah_${AH_VERSION}_linux_amd64.tar.gz | ||||||
|  |           chmod +x ./ah | ||||||
|  |           sudo mv ./ah /usr/bin/ah | ||||||
|  |           rm LICENSE | ||||||
|  |       - name: ah lint | ||||||
|  |         run: | | ||||||
|  |           ah lint | ||||||
|  |  | ||||||
|   pr-build: |   pr-build: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
| @@ -45,11 +57,10 @@ jobs: | |||||||
|       - name: Set up Docker Buildx |       - name: Set up Docker Buildx | ||||||
|         uses: docker/setup-buildx-action@v3 |         uses: docker/setup-buildx-action@v3 | ||||||
|  |  | ||||||
|       - name: "GHCR Build" |       - name: GHCR Build | ||||||
|         id: docker_build |         id: docker_build | ||||||
|         uses: docker/build-push-action@v5 |         uses: docker/build-push-action@v6 | ||||||
|         with: |         with: | ||||||
|           push: false |           push: false | ||||||
|           platforms: linux/amd64,linux/arm64 |           platforms: linux/amd64,linux/arm64 | ||||||
|           tags: ghcr.io/lerentis/bitwarden-crd-operator:dev |           tags: ghcr.io/lerentis/bitwarden-crd-operator:dev | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,44 +1,29 @@ | |||||||
| FROM alpine:3.18.4 | FROM alpine:3.19.1 | ||||||
|  |  | ||||||
| LABEL org.opencontainers.image.source=https://github.com/Lerentis/bitwarden-crd-operator | LABEL org.opencontainers.image.source=https://github.com/Lerentis/bitwarden-crd-operator | ||||||
| LABEL org.opencontainers.image.description="Kubernetes Operator to create k8s secrets from bitwarden" | LABEL org.opencontainers.image.description="Kubernetes Operator to create k8s secrets from bitwarden" | ||||||
| LABEL org.opencontainers.image.licenses=MIT | LABEL org.opencontainers.image.licenses=MIT | ||||||
|  |  | ||||||
| ARG PYTHON_VERSION=3.11.6-r0 | ARG PYTHON_VERSION=3.11.9-r0 | ||||||
| ARG PIP_VERSION=23.1.2-r0 | ARG PIP_VERSION=23.3.1-r0 | ||||||
| ARG GCOMPAT_VERSION=1.1.0-r1 | ARG GCOMPAT_VERSION=1.1.0-r4 | ||||||
| ARG LIBCRYPTO_VERSION=3.1.3-r0 | ARG LIBCRYPTO_VERSION=3.1.4-r5 | ||||||
| ARG BW_VERSION=2023.1.0 | ARG BW_VERSION=2023.7.0 | ||||||
|  | ARG NODE_VERSION=20.12.1-r0 | ||||||
|  |  | ||||||
| COPY requirements.txt /requirements.txt | COPY requirements.txt /requirements.txt | ||||||
|  |  | ||||||
| RUN set -eux; \ | RUN set -eux; \ | ||||||
|     apk add --virtual build-dependencies wget unzip; \ |     apk update; \ | ||||||
|     ARCH="$(apk --print-arch)"; \ |     apk del nodejs-current; \ | ||||||
|     case "${ARCH}" in \ |     apk add nodejs=${NODE_VERSION} npm; \ | ||||||
|        aarch64|arm64) \ |  | ||||||
|           apk add npm; \ |  | ||||||
|     npm install -g @bitwarden/cli@${BW_VERSION}; \ |     npm install -g @bitwarden/cli@${BW_VERSION}; \ | ||||||
|          ;; \ |  | ||||||
|        amd64|x86_64) \ |  | ||||||
|           cd /tmp; \ |  | ||||||
|           wget https://github.com/bitwarden/clients/releases/download/cli-v${BW_VERSION}/bw-linux-${BW_VERSION}.zip; \ |  | ||||||
|           unzip /tmp/bw-linux-${BW_VERSION}.zip; \ |  | ||||||
|           mv /tmp/bw /usr/local/bin/bw; \ |  | ||||||
|           chmod +x /usr/local/bin/bw; \ |  | ||||||
|          ;; \ |  | ||||||
|        *) \ |  | ||||||
|          echo "Unsupported arch: ${ARCH}"; \ |  | ||||||
|          exit 1; \ |  | ||||||
|          ;; \ |  | ||||||
|     esac; \ |  | ||||||
|     apk del --purge build-dependencies; \ |  | ||||||
|     addgroup -S -g 1000 bw-operator; \ |     addgroup -S -g 1000 bw-operator; \ | ||||||
|     adduser -S -D -u 1000 -G bw-operator bw-operator; \ |     adduser -S -D -u 1000 -G bw-operator bw-operator; \ | ||||||
|     mkdir -p /home/bw-operator; \ |     mkdir -p /home/bw-operator; \ | ||||||
|     chown -R bw-operator /home/bw-operator; \ |     chown -R bw-operator /home/bw-operator; \ | ||||||
|     apk add gcc musl-dev libstdc++ gcompat=${GCOMPAT_VERSION} python3=${PYTHON_VERSION} py3-pip=${PIP_VERSION} libcrypto3=${LIBCRYPTO_VERSION}; \ |     apk add gcc musl-dev libstdc++ gcompat=${GCOMPAT_VERSION} python3=${PYTHON_VERSION} py3-pip=${PIP_VERSION} libcrypto3=${LIBCRYPTO_VERSION}; \ | ||||||
|     pip install -r /requirements.txt --no-warn-script-location; \ |     pip install -r /requirements.txt --no-warn-script-location --break-system-packages; \ | ||||||
|     rm /requirements.txt; \ |     rm /requirements.txt; \ | ||||||
|     apk del --purge gcc musl-dev libstdc++; |     apk del --purge gcc musl-dev libstdc++; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
									
									
									
									
								
							| @@ -56,23 +56,29 @@ And you are set to create your first secret using this operator. For that you ne | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta4" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: BitwardenSecret | kind: BitwardenSecret | ||||||
| metadata: | metadata: | ||||||
|   name: name-of-your-management-object |   name: name-of-your-management-object | ||||||
| spec: | spec: | ||||||
|   content: |   content: | ||||||
|     - element: |     - element: | ||||||
|         secretName: nameOfTheFieldInBitwarden # for example username |         secretName: nameOfTheFieldInBitwarden # for example username or filename | ||||||
|         secretRef: nameOfTheKeyInTheSecretToBeCreated  |         secretRef: nameOfTheKeyInTheSecretToBeCreated  | ||||||
|         secretScope: login # for custom entries on bitwarden use 'fields'  |         secretScope: login # for custom entries on bitwarden use 'fields, for attachments use attachment'  | ||||||
|     - element: |     - element: | ||||||
|         secretName: nameOfAnotherFieldInBitwarden # for example password |         secretName: nameOfAnotherFieldInBitwarden # for example password or filename | ||||||
|         secretRef: nameOfAnotherKeyInTheSecretToBeCreated  |         secretRef: nameOfAnotherKeyInTheSecretToBeCreated  | ||||||
|         secretScope: login # for custom entries on bitwarden use 'fields'  |         secretScope: login # for custom entries on bitwarden use 'fields, for attachments use attachment'  | ||||||
|   id: "A Secret ID from bitwarden" |   id: "A Secret ID from bitwarden" | ||||||
|   name: "Name of the secret to be created" |   name: "Name of the secret to be created" | ||||||
|  |   secretType: # Optional (Default: Opaque) | ||||||
|   namespace: "Namespace of the secret to be created" |   namespace: "Namespace of the secret to be created" | ||||||
|  |   labels: # Optional | ||||||
|  |     key: value | ||||||
|  |   annotations: # Optional | ||||||
|  |     key: value | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| The ID can be extracted from the browser when you open a item the ID is in the URL. The resulting secret looks something like this: | The ID can be extracted from the browser when you open a item the ID is in the URL. The resulting secret looks something like this: | ||||||
| @@ -87,6 +93,8 @@ metadata: | |||||||
|   annotations: |   annotations: | ||||||
|     managed: bitwarden-secrets.lerentis.uploadfilter24.eu |     managed: bitwarden-secrets.lerentis.uploadfilter24.eu | ||||||
|     managedObject: bw-operator/test |     managedObject: bw-operator/test | ||||||
|  |   labels: | ||||||
|  |     key: value | ||||||
|   name: name-of-your-management-object |   name: name-of-your-management-object | ||||||
|   namespace: default |   namespace: default | ||||||
| type: Opaque | type: Opaque | ||||||
| @@ -98,7 +106,7 @@ For managing registry credentials, or pull secrets, you can create another kind | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta4" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: RegistryCredential | kind: RegistryCredential | ||||||
| metadata: | metadata: | ||||||
|   name: name-of-your-management-object |   name: name-of-your-management-object | ||||||
| @@ -109,6 +117,10 @@ spec: | |||||||
|   id: "A Secret ID from bitwarden" |   id: "A Secret ID from bitwarden" | ||||||
|   name: "Name of the secret to be created" |   name: "Name of the secret to be created" | ||||||
|   namespace: "Namespace of the secret to be created" |   namespace: "Namespace of the secret to be created" | ||||||
|  |   labels: # Optional | ||||||
|  |     key: value | ||||||
|  |   annotations: # Optional | ||||||
|  |     key: value | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| The resulting secret looks something like this: | The resulting secret looks something like this: | ||||||
| @@ -122,6 +134,8 @@ metadata: | |||||||
|   annotations: |   annotations: | ||||||
|     managed: bitwarden-secrets.lerentis.uploadfilter24.eu |     managed: bitwarden-secrets.lerentis.uploadfilter24.eu | ||||||
|     managedObject: bw-operator/test |     managedObject: bw-operator/test | ||||||
|  |   labels: | ||||||
|  |     key: value | ||||||
|   name: name-of-your-management-object |   name: name-of-your-management-object | ||||||
|   namespace: default |   namespace: default | ||||||
| type: dockerconfigjson | type: dockerconfigjson | ||||||
| @@ -133,14 +147,19 @@ One of the more freely defined types that can be used with this operator you can | |||||||
|  |  | ||||||
| ```yaml | ```yaml | ||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta4" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: BitwardenTemplate | kind: BitwardenTemplate | ||||||
| metadata: | metadata: | ||||||
|   name: name-of-your-management-object |   name: name-of-your-management-object | ||||||
| spec: | spec: | ||||||
|   filename: "Key of the secret to be created" |   filename: "Key of the secret to be created" | ||||||
|   name: "Name of the secret to be created" |   name: "Name of the secret to be created" | ||||||
|  |   secretType: # Optional (Default: Opaque) | ||||||
|   namespace: "Namespace of the secret to be created" |   namespace: "Namespace of the secret to be created" | ||||||
|  |   labels: # Optional | ||||||
|  |     key: value | ||||||
|  |   annotations: # Optional | ||||||
|  |     key: value | ||||||
|   template: | |   template: | | ||||||
|     --- |     --- | ||||||
|     api: |     api: | ||||||
| @@ -164,6 +183,8 @@ metadata: | |||||||
|   annotations: |   annotations: | ||||||
|     managed: bitwarden-template.lerentis.uploadfilter24.eu |     managed: bitwarden-template.lerentis.uploadfilter24.eu | ||||||
|     managedObject: namespace/name-of-your-management-object |     managedObject: namespace/name-of-your-management-object | ||||||
|  |   labels: | ||||||
|  |     key: value | ||||||
|   name: Name of the secret to be created |   name: Name of the secret to be created | ||||||
|   namespace: Namespace of the secret to be created |   namespace: Namespace of the secret to be created | ||||||
| type: Opaque | type: Opaque | ||||||
|   | |||||||
| @@ -4,9 +4,9 @@ description: Deploy the Bitwarden CRD Operator | |||||||
|  |  | ||||||
| type: application | type: application | ||||||
|  |  | ||||||
| version: "v0.11.0" | version: "v0.13.0" | ||||||
|  |  | ||||||
| appVersion: "0.10.0" | appVersion: "0.12.0" | ||||||
|  |  | ||||||
| keywords: | keywords: | ||||||
|   - operator |   - operator | ||||||
| @@ -32,22 +32,22 @@ annotations: | |||||||
|       url: https://github.com/Lerentis/bitwarden-crd-operator |       url: https://github.com/Lerentis/bitwarden-crd-operator | ||||||
|   artifacthub.io/crds: | |   artifacthub.io/crds: | | ||||||
|     - kind: BitwardenSecret |     - kind: BitwardenSecret | ||||||
|       version: v1beta5 |       version: v1beta7 | ||||||
|       name: bitwarden-secret |       name: bitwarden-secret | ||||||
|       displayName: Bitwarden Secret |       displayName: Bitwarden Secret | ||||||
|       description: Management Object to create secrets from bitwarden |       description: Management Object to create secrets from bitwarden | ||||||
|     - kind: RegistryCredential |     - kind: RegistryCredential | ||||||
|       version: v1beta5 |       version: v1beta7 | ||||||
|       name: registry-credential |       name: registry-credential | ||||||
|       displayName: Regestry Credentials |       displayName: Regestry Credentials | ||||||
|       description: Management Object to create regestry secrets from bitwarden |       description: Management Object to create regestry secrets from bitwarden | ||||||
|     - kind: BitwardenTemplate |     - kind: BitwardenTemplate | ||||||
|       version: v1beta5 |       version: v1beta7 | ||||||
|       name: bitwarden-template |       name: bitwarden-template | ||||||
|       displayName: Bitwarden Template |       displayName: Bitwarden Template | ||||||
|       description: Management Object to create secrets from a jinja template with a bitwarden lookup |       description: Management Object to create secrets from a jinja template with a bitwarden lookup | ||||||
|   artifacthub.io/crdsExamples: | |   artifacthub.io/crdsExamples: | | ||||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta5 |     - apiVersion: lerentis.uploadfilter24.eu/v1beta7 | ||||||
|       kind: BitwardenSecret |       kind: BitwardenSecret | ||||||
|       metadata: |       metadata: | ||||||
|         name: test |         name: test | ||||||
| @@ -61,10 +61,13 @@ annotations: | |||||||
|               secretRef: passwordOfUser |               secretRef: passwordOfUser | ||||||
|         id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" |         id: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" | ||||||
|         name: "test-secret" |         name: "test-secret" | ||||||
|  |         secretType: Obaque #Optional | ||||||
|         namespace: "default" |         namespace: "default" | ||||||
|         labels: |         labels: | ||||||
|           key: value |           key: value | ||||||
|     - apiVersion: lerentis.uploadfilter24.eu/v1beta5 |         annotations: | ||||||
|  |           key: value | ||||||
|  |     - apiVersion: lerentis.uploadfilter24.eu/v1beta7 | ||||||
|       kind: RegistryCredential |       kind: RegistryCredential | ||||||
|       metadata: |       metadata: | ||||||
|         name: test |         name: test | ||||||
| @@ -77,16 +80,21 @@ annotations: | |||||||
|         namespace: "default" |         namespace: "default" | ||||||
|         labels: |         labels: | ||||||
|           key: value |           key: value | ||||||
|     - apiVersion: "lerentis.uploadfilter24.eu/v1beta5" |         annotations: | ||||||
|  |           key: value | ||||||
|  |     - apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
|       kind: BitwardenTemplate |       kind: BitwardenTemplate | ||||||
|       metadata: |       metadata: | ||||||
|         name: test |         name: test | ||||||
|       spec: |       spec: | ||||||
|         filename: "config.yaml" |         filename: "config.yaml" | ||||||
|         name: "test-regcred" |         name: "test-regcred" | ||||||
|  |         secretType: Obaque #Optional | ||||||
|         namespace: "default" |         namespace: "default" | ||||||
|         labels: |         labels: | ||||||
|           key: value |           key: value | ||||||
|  |         annotations: | ||||||
|  |           key: value | ||||||
|         template: | |         template: | | ||||||
|           --- |           --- | ||||||
|           api: |           api: | ||||||
| @@ -101,8 +109,12 @@ annotations: | |||||||
|   artifacthub.io/operator: "true" |   artifacthub.io/operator: "true" | ||||||
|   artifacthub.io/containsSecurityUpdates: "false" |   artifacthub.io/containsSecurityUpdates: "false" | ||||||
|   artifacthub.io/changes: | |   artifacthub.io/changes: | | ||||||
|     - kind: changed |     - kind: added | ||||||
|       description: "Added the possibility to add labels to generated secrets" |       description: "Allow custom type for generated secrets" | ||||||
|  |     - kind: added | ||||||
|  |       description: "Allow attachments in generated secrets" | ||||||
|  |     - kind: added | ||||||
|  |       description: "Allow custom type in templated secrets" | ||||||
|   artifacthub.io/images: | |   artifacthub.io/images: | | ||||||
|     - name: bitwarden-crd-operator |     - name: bitwarden-crd-operator | ||||||
|       image: ghcr.io/lerentis/bitwarden-crd-operator:0.10.0 |       image: ghcr.io/lerentis/bitwarden-crd-operator:0.12.0 | ||||||
|   | |||||||
| @@ -14,8 +14,9 @@ spec: | |||||||
|       - bws |       - bws | ||||||
|   versions: |   versions: | ||||||
|     - name: v1beta4 |     - name: v1beta4 | ||||||
|       served: false |       served: true | ||||||
|       storage: true |       storage: false | ||||||
|  |       deprecated: true | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|           type: object |           type: object | ||||||
| @@ -51,7 +52,8 @@ spec: | |||||||
|                 - name |                 - name | ||||||
|     - name: v1beta5 |     - name: v1beta5 | ||||||
|       served: true |       served: true | ||||||
|       storage: true |       storage: false | ||||||
|  |       deprecated: true | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|           type: object |           type: object | ||||||
| @@ -82,21 +84,95 @@ spec: | |||||||
|                 name: |                 name: | ||||||
|                   type: string |                   type: string | ||||||
|                 labels: |                 labels: | ||||||
|                   type: array |  | ||||||
|                   items: |  | ||||||
|                   type: object |                   type: object | ||||||
|                     properties: |  | ||||||
|                       json: |  | ||||||
|                   x-kubernetes-preserve-unknown-fields: true |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |               required: | ||||||
|  |                 - id | ||||||
|  |                 - namespace | ||||||
|  |                 - name | ||||||
|  |     - name: v1beta6 | ||||||
|  |       served: true | ||||||
|  |       storage: false | ||||||
|  |       deprecated: true | ||||||
|  |       schema: | ||||||
|  |         openAPIV3Schema: | ||||||
|           type: object |           type: object | ||||||
|           properties: |           properties: | ||||||
|             spec: |             spec: | ||||||
|               type: object |               type: object | ||||||
|               properties: |               properties: | ||||||
|                               foo: |                 content: | ||||||
|  |                   type: array | ||||||
|  |                   items: | ||||||
|  |                     type: object | ||||||
|  |                     properties: | ||||||
|  |                       element: | ||||||
|  |                         type: object | ||||||
|  |                         properties: | ||||||
|  |                           secretName: | ||||||
|                             type: string |                             type: string | ||||||
|                               bar: |                           secretRef: | ||||||
|                             type: string |                             type: string | ||||||
|  |                           secretScope: | ||||||
|  |                             type: string | ||||||
|  |                         required: | ||||||
|  |                           - secretName | ||||||
|  |                 id: | ||||||
|  |                   type: string | ||||||
|  |                 namespace: | ||||||
|  |                   type: string | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 labels: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |                 annotations: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |               required: | ||||||
|  |                 - id | ||||||
|  |                 - namespace | ||||||
|  |                 - name | ||||||
|  |     - name: v1beta7 | ||||||
|  |       served: true | ||||||
|  |       storage: true | ||||||
|  |       schema: | ||||||
|  |         openAPIV3Schema: | ||||||
|  |           type: object | ||||||
|  |           properties: | ||||||
|  |             spec: | ||||||
|  |               type: object | ||||||
|  |               properties: | ||||||
|  |                 content: | ||||||
|  |                   type: array | ||||||
|  |                   items: | ||||||
|  |                     type: object | ||||||
|  |                     properties: | ||||||
|  |                       element: | ||||||
|  |                         type: object | ||||||
|  |                         properties: | ||||||
|  |                           secretName: | ||||||
|  |                             type: string | ||||||
|  |                           secretRef: | ||||||
|  |                             type: string | ||||||
|  |                           secretScope: | ||||||
|  |                             type: string | ||||||
|  |                         required: | ||||||
|  |                           - secretName | ||||||
|  |                 id: | ||||||
|  |                   type: string | ||||||
|  |                 namespace: | ||||||
|  |                   type: string | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 secretType:  | ||||||
|  |                   type: string | ||||||
|  |                 labels: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |                 annotations: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|               required: |               required: | ||||||
|                 - id |                 - id | ||||||
|                 - namespace |                 - namespace | ||||||
|   | |||||||
| @@ -14,8 +14,9 @@ spec: | |||||||
|       - bwt |       - bwt | ||||||
|   versions: |   versions: | ||||||
|     - name: v1beta4 |     - name: v1beta4 | ||||||
|       served: false |       served: true | ||||||
|       storage: true |       storage: false | ||||||
|  |       deprecated: true | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|           type: object |           type: object | ||||||
| @@ -38,7 +39,8 @@ spec: | |||||||
|                 - name |                 - name | ||||||
|     - name: v1beta5 |     - name: v1beta5 | ||||||
|       served: true |       served: true | ||||||
|       storage: true |       storage: false | ||||||
|  |       deprecated: true | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|           type: object |           type: object | ||||||
| @@ -55,21 +57,69 @@ spec: | |||||||
|                 name: |                 name: | ||||||
|                   type: string |                   type: string | ||||||
|                 labels: |                 labels: | ||||||
|                   type: array |  | ||||||
|                   items: |  | ||||||
|                   type: object |                   type: object | ||||||
|                     properties: |  | ||||||
|                       json: |  | ||||||
|                   x-kubernetes-preserve-unknown-fields: true |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|                         type: object |               required: | ||||||
|                         properties: |                 - filename | ||||||
|                           spec: |                 - template | ||||||
|                             type: object |                 - namespace | ||||||
|                             properties: |                 - name | ||||||
|                               foo: |     - name: v1beta6 | ||||||
|                                 type: string |       served: true | ||||||
|                               bar: |       storage: false | ||||||
|                                 type: string |       deprecated: true | ||||||
|  |       schema: | ||||||
|  |         openAPIV3Schema: | ||||||
|  |           type: object | ||||||
|  |           properties: | ||||||
|  |             spec: | ||||||
|  |               type: object | ||||||
|  |               properties: | ||||||
|  |                 filename: | ||||||
|  |                   type: string | ||||||
|  |                 template: | ||||||
|  |                   type: string | ||||||
|  |                 namespace: | ||||||
|  |                   type: string | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 labels: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |                 annotations: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |               required: | ||||||
|  |                 - filename | ||||||
|  |                 - template | ||||||
|  |                 - namespace | ||||||
|  |                 - name | ||||||
|  |     - name: v1beta7 | ||||||
|  |       served: true | ||||||
|  |       storage: true | ||||||
|  |       schema: | ||||||
|  |         openAPIV3Schema: | ||||||
|  |           type: object | ||||||
|  |           properties: | ||||||
|  |             spec: | ||||||
|  |               type: object | ||||||
|  |               properties: | ||||||
|  |                 filename: | ||||||
|  |                   type: string | ||||||
|  |                 template: | ||||||
|  |                   type: string | ||||||
|  |                 namespace: | ||||||
|  |                   type: string | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 secretType:  | ||||||
|  |                   type: string | ||||||
|  |                 labels: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |                 annotations: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|               required: |               required: | ||||||
|                 - filename |                 - filename | ||||||
|                 - template |                 - template | ||||||
|   | |||||||
| @@ -14,8 +14,9 @@ spec: | |||||||
|       - rgc |       - rgc | ||||||
|   versions: |   versions: | ||||||
|     - name: v1beta4 |     - name: v1beta4 | ||||||
|       served: false |       served: true | ||||||
|       storage: true |       storage: false | ||||||
|  |       deprecated: true | ||||||
|       schema: |       schema: | ||||||
|         openAPIV3Schema: |         openAPIV3Schema: | ||||||
|           type: object |           type: object | ||||||
| @@ -43,6 +44,75 @@ spec: | |||||||
|                 - passwordRef |                 - passwordRef | ||||||
|                 - registry |                 - registry | ||||||
|     - name: v1beta5 |     - name: v1beta5 | ||||||
|  |       served: true | ||||||
|  |       storage: false | ||||||
|  |       deprecated: true | ||||||
|  |       schema: | ||||||
|  |         openAPIV3Schema: | ||||||
|  |           type: object | ||||||
|  |           properties: | ||||||
|  |             spec: | ||||||
|  |               type: object | ||||||
|  |               properties: | ||||||
|  |                 usernameRef: | ||||||
|  |                   type: string | ||||||
|  |                 passwordRef: | ||||||
|  |                   type: string | ||||||
|  |                 registry: | ||||||
|  |                   type: string | ||||||
|  |                 id: | ||||||
|  |                   type: string | ||||||
|  |                 namespace: | ||||||
|  |                   type: string | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 labels: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |               required: | ||||||
|  |                 - id | ||||||
|  |                 - namespace | ||||||
|  |                 - name | ||||||
|  |                 - usernameRef | ||||||
|  |                 - passwordRef | ||||||
|  |                 - registry | ||||||
|  |     - name: v1beta6 | ||||||
|  |       served: true | ||||||
|  |       storage: false | ||||||
|  |       deprecated: true | ||||||
|  |       schema: | ||||||
|  |         openAPIV3Schema: | ||||||
|  |           type: object | ||||||
|  |           properties: | ||||||
|  |             spec: | ||||||
|  |               type: object | ||||||
|  |               properties: | ||||||
|  |                 usernameRef: | ||||||
|  |                   type: string | ||||||
|  |                 passwordRef: | ||||||
|  |                   type: string | ||||||
|  |                 registry: | ||||||
|  |                   type: string | ||||||
|  |                 id: | ||||||
|  |                   type: string | ||||||
|  |                 namespace: | ||||||
|  |                   type: string | ||||||
|  |                 name: | ||||||
|  |                   type: string | ||||||
|  |                 labels: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |                 annotations: | ||||||
|  |                   type: object | ||||||
|  |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |               required: | ||||||
|  |                 - id | ||||||
|  |                 - namespace | ||||||
|  |                 - name | ||||||
|  |                 - usernameRef | ||||||
|  |                 - passwordRef | ||||||
|  |                 - registry | ||||||
|  |     - name: v1beta7 | ||||||
|       served: true |       served: true | ||||||
|       storage: true |       storage: true | ||||||
|       schema: |       schema: | ||||||
| @@ -65,21 +135,11 @@ spec: | |||||||
|                 name: |                 name: | ||||||
|                   type: string |                   type: string | ||||||
|                 labels: |                 labels: | ||||||
|                   type: array |  | ||||||
|                   items: |  | ||||||
|                   type: object |                   type: object | ||||||
|                     properties: |  | ||||||
|                       json: |  | ||||||
|                   x-kubernetes-preserve-unknown-fields: true |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|  |                 annotations: | ||||||
|                   type: object |                   type: object | ||||||
|                         properties: |                   x-kubernetes-preserve-unknown-fields: true | ||||||
|                           spec: |  | ||||||
|                             type: object |  | ||||||
|                             properties: |  | ||||||
|                               foo: |  | ||||||
|                                 type: string |  | ||||||
|                               bar: |  | ||||||
|                                 type: string |  | ||||||
|               required: |               required: | ||||||
|                 - id |                 - id | ||||||
|                 - namespace |                 - namespace | ||||||
|   | |||||||
| @@ -8,6 +8,8 @@ spec: | |||||||
|   {{- if not .Values.autoscaling.enabled }} |   {{- if not .Values.autoscaling.enabled }} | ||||||
|   replicas: {{ .Values.replicaCount }} |   replicas: {{ .Values.replicaCount }} | ||||||
|   {{- end }} |   {{- end }} | ||||||
|  |   strategy:  | ||||||
|  |     type: {{ .Values.deploymentStrategy }} | ||||||
|   selector: |   selector: | ||||||
|     matchLabels: |     matchLabels: | ||||||
|       {{- include "bitwarden-crd-operator.selectorLabels" . | nindent 6 }} |       {{- include "bitwarden-crd-operator.selectorLabels" . | nindent 6 }} | ||||||
|   | |||||||
| @@ -14,6 +14,8 @@ imagePullSecrets: [] | |||||||
| nameOverride: "" | nameOverride: "" | ||||||
| fullnameOverride: "" | fullnameOverride: "" | ||||||
|  |  | ||||||
|  | deploymentStrategy: "Recreate" | ||||||
|  |  | ||||||
| # env: | # env: | ||||||
| #   - name: BW_FORCE_SYNC | #   - name: BW_FORCE_SYNC | ||||||
| #     value: "false" | #     value: "false" | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								example.yaml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								example.yaml
									
									
									
									
									
								
							| @@ -1,8 +1,9 @@ | |||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: BitwardenSecret | kind: BitwardenSecret | ||||||
| metadata: | metadata: | ||||||
|   name: test |   name: test | ||||||
|  |   namespace: default | ||||||
| spec: | spec: | ||||||
|   content: |   content: | ||||||
|     - element: |     - element: | ||||||
| @@ -15,11 +16,15 @@ spec: | |||||||
|         secretScope: login |         secretScope: login | ||||||
|   id: "88781348-c81c-4367-9801-550360c21295" |   id: "88781348-c81c-4367-9801-550360c21295" | ||||||
|   name: "test-secret" |   name: "test-secret" | ||||||
|  |   secretType: Opaque | ||||||
|   namespace: "default" |   namespace: "default" | ||||||
|   labels: |   labels: | ||||||
|     - key: value |     key: value | ||||||
|  |     app: example-app | ||||||
|  |   annotations: | ||||||
|  |     custom.annotation: is-used | ||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta5" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: BitwardenSecret | kind: BitwardenSecret | ||||||
| metadata: | metadata: | ||||||
|   name: test-scope |   name: test-scope | ||||||
| @@ -32,5 +37,3 @@ spec: | |||||||
|   id: "466fc4b0-ffca-4444-8d88-b59d4de3d928" |   id: "466fc4b0-ffca-4444-8d88-b59d4de3d928" | ||||||
|   name: "test-scope" |   name: "test-scope" | ||||||
|   namespace: "default" |   namespace: "default" | ||||||
|   labels: |  | ||||||
|     - key: value |  | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta4" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: RegistryCredential | kind: RegistryCredential | ||||||
| metadata: | metadata: | ||||||
|   name: test |   name: test | ||||||
| @@ -10,3 +10,8 @@ spec: | |||||||
|   id: "3b249ec7-9ce7-440a-9558-f34f3ab10680" |   id: "3b249ec7-9ce7-440a-9558-f34f3ab10680" | ||||||
|   name: "test-regcred" |   name: "test-regcred" | ||||||
|   namespace: "default" |   namespace: "default" | ||||||
|  |   labels: | ||||||
|  |     namespace: default | ||||||
|  |     tenant: example-team | ||||||
|  |   annotations: | ||||||
|  |     custom.annotation: is-used | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| --- | --- | ||||||
| apiVersion: "lerentis.uploadfilter24.eu/v1beta4" | apiVersion: "lerentis.uploadfilter24.eu/v1beta7" | ||||||
| kind: BitwardenTemplate | kind: BitwardenTemplate | ||||||
| metadata: | metadata: | ||||||
|   name: test |   name: test | ||||||
| @@ -7,6 +7,11 @@ spec: | |||||||
|   filename: "config.yaml" |   filename: "config.yaml" | ||||||
|   name: "test-template" |   name: "test-template" | ||||||
|   namespace: "default" |   namespace: "default" | ||||||
|  |   labels: | ||||||
|  |     key: value | ||||||
|  |     app: example-app | ||||||
|  |   annotations: | ||||||
|  |     custom.annotation: is-used | ||||||
|   template: | |   template: | | ||||||
|     --- |     --- | ||||||
|     api: |     api: | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| kopf==1.36.2 | kopf==1.37.2 | ||||||
| kubernetes==26.1.0 | kubernetes==29.0.0 | ||||||
| Jinja2==3.1.2 | Jinja2==3.1.4 | ||||||
| schedule==1.2.1 | schedule==1.2.2 | ||||||
| @@ -1,8 +1,10 @@ | |||||||
| apiVersion: skaffold/v4beta5 | apiVersion: skaffold/v4beta9 | ||||||
| kind: Config | kind: Config | ||||||
| metadata: | metadata: | ||||||
|   name: bitwarden-crd-operator |   name: bitwarden-crd-operator | ||||||
| build: | build: | ||||||
|  |   tagPolicy: | ||||||
|  |     sha256: {} | ||||||
|   artifacts: |   artifacts: | ||||||
|     - image: ghcr.io/lerentis/bitwarden-crd-operator |     - image: ghcr.io/lerentis/bitwarden-crd-operator | ||||||
|       docker: |       docker: | ||||||
| @@ -13,5 +15,43 @@ deploy: | |||||||
|       - name: bitwarden-crd-operator |       - name: bitwarden-crd-operator | ||||||
|         chartPath: charts/bitwarden-crd-operator |         chartPath: charts/bitwarden-crd-operator | ||||||
|         valuesFiles: |         valuesFiles: | ||||||
|           - env/values.yaml |           - ./charts/bitwarden-crd-operator/myvalues.yaml | ||||||
|         version: v0.7.4 |         setValueTemplates: | ||||||
|  |           image.repository: "{{.IMAGE_REPO_ghcr_io_lerentis_bitwarden_crd_operator}}" | ||||||
|  |           image.tag: "{{.IMAGE_TAG_ghcr_io_lerentis_bitwarden_crd_operator}}@{{.IMAGE_DIGEST_ghcr_io_lerentis_bitwarden_crd_operator}}" | ||||||
|  |     hooks: | ||||||
|  |       after: | ||||||
|  |         - host: | ||||||
|  |             command: | ||||||
|  |               - kubectl | ||||||
|  |               - apply | ||||||
|  |               - -f | ||||||
|  |               - ./example*.yaml | ||||||
|  |         - host: | ||||||
|  |             command: | ||||||
|  |               - sleep | ||||||
|  |               - '5' | ||||||
|  |         - host: | ||||||
|  |             command: | ||||||
|  |               - kubectl | ||||||
|  |               - get | ||||||
|  |               - secret | ||||||
|  |               - test-regcred | ||||||
|  |         - host: | ||||||
|  |             command: | ||||||
|  |               - kubectl | ||||||
|  |               - get | ||||||
|  |               - secret | ||||||
|  |               - test-scope | ||||||
|  |         - host: | ||||||
|  |             command: | ||||||
|  |               - kubectl | ||||||
|  |               - get | ||||||
|  |               - secret | ||||||
|  |               - test-secret | ||||||
|  |         - host: | ||||||
|  |             command: | ||||||
|  |               - kubectl | ||||||
|  |               - get | ||||||
|  |               - secret | ||||||
|  |               - test-template | ||||||
|   | |||||||
| @@ -45,6 +45,7 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): | |||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|     labels = spec.get('labels') |     labels = spec.get('labels') | ||||||
|  |     custom_annotations = spec.get('annotations') | ||||||
|  |  | ||||||
|     unlock_bw(logger) |     unlock_bw(logger) | ||||||
|     logger.info(f"Locking up secret with ID: {id}") |     logger.info(f"Locking up secret with ID: {id}") | ||||||
| @@ -57,6 +58,9 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): | |||||||
|         "managedObject": f"{namespace}/{name}" |         "managedObject": f"{namespace}/{name}" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if custom_annotations: | ||||||
|  |         annotations.update(custom_annotations) | ||||||
|  |  | ||||||
|     if not labels: |     if not labels: | ||||||
|         labels = {} |         labels = {} | ||||||
|  |  | ||||||
| @@ -71,6 +75,11 @@ def create_managed_registry_secret(spec, name, namespace, logger, **kwargs): | |||||||
|         password_ref, |         password_ref, | ||||||
|         registry) |         registry) | ||||||
|      |      | ||||||
|  |     # Garbage collection will delete the generated secret if the owner | ||||||
|  |     # Is not in the same namespace as the generated secret | ||||||
|  |     if secret_namespace == namespace: | ||||||
|  |         kopf.append_owner_reference(secret) | ||||||
|  |  | ||||||
|     api.create_namespaced_secret( |     api.create_namespaced_secret( | ||||||
|         secret_namespace, secret |         secret_namespace, secret | ||||||
|     ) |     ) | ||||||
| @@ -96,6 +105,8 @@ def update_managed_registry_secret( | |||||||
|     id = spec.get('id') |     id = spec.get('id') | ||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|  |     labels = spec.get('labels') | ||||||
|  |     custom_annotations = spec.get('annotations') | ||||||
|  |  | ||||||
|     old_config = None |     old_config = None | ||||||
|     old_secret_name = None |     old_secret_name = None | ||||||
| @@ -132,9 +143,16 @@ def update_managed_registry_secret( | |||||||
|         "managed": "registry-credential.lerentis.uploadfilter24.eu", |         "managed": "registry-credential.lerentis.uploadfilter24.eu", | ||||||
|         "managedObject": f"{namespace}/{name}" |         "managedObject": f"{namespace}/{name}" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if custom_annotations: | ||||||
|  |         annotations.update(custom_annotations) | ||||||
|  |  | ||||||
|  |     if not labels: | ||||||
|  |         labels = {} | ||||||
|  |  | ||||||
|     secret = kubernetes.client.V1Secret() |     secret = kubernetes.client.V1Secret() | ||||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( |     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||||
|         name=secret_name, annotations=annotations) |         name=secret_name, annotations=annotations, labels=labels) | ||||||
|     secret = create_dockerlogin( |     secret = create_dockerlogin( | ||||||
|         logger, |         logger, | ||||||
|         secret, |         secret, | ||||||
| @@ -142,16 +160,25 @@ def update_managed_registry_secret( | |||||||
|         username_ref, |         username_ref, | ||||||
|         password_ref, |         password_ref, | ||||||
|         registry) |         registry) | ||||||
|  |      | ||||||
|  |     # Garbage collection will delete the generated secret if the owner | ||||||
|  |     # Is not in the same namespace as the generated secret | ||||||
|  |     if secret_namespace == namespace: | ||||||
|  |         kopf.append_owner_reference(secret) | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         obj = api.replace_namespaced_secret( |         api.replace_namespaced_secret( | ||||||
|             name=secret_name, |             name=secret_name, | ||||||
|             body=secret, |             body=secret, | ||||||
|             namespace="{}".format(secret_namespace)) |             namespace="{}".format(secret_namespace)) | ||||||
|         logger.info( |         logger.info( | ||||||
|             f"Secret {secret_namespace}/{secret_name} has been updated") |             f"Secret {secret_namespace}/{secret_name} has been updated") | ||||||
|     except BaseException: |     except BaseException as e: | ||||||
|         logger.warn( |         logger.warn( | ||||||
|             f"Could not update secret {secret_namespace}/{secret_name}!") |             f"Could not update secret {secret_namespace}/{secret_name}!") | ||||||
|  |         logger.warn( | ||||||
|  |             f"Exception: {e}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @kopf.on.delete('registry-credential.lerentis.uploadfilter24.eu') | @kopf.on.delete('registry-credential.lerentis.uploadfilter24.eu') | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								src/kv.py
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								src/kv.py
									
									
									
									
									
								
							| @@ -3,10 +3,9 @@ import kubernetes | |||||||
| import base64 | import base64 | ||||||
| import json | import json | ||||||
|  |  | ||||||
| from utils.utils import unlock_bw, get_secret_from_bitwarden, parse_login_scope, parse_fields_scope, bw_sync_interval | from utils.utils import unlock_bw, get_secret_from_bitwarden, parse_login_scope, parse_fields_scope, get_attachment, bw_sync_interval | ||||||
|  |  | ||||||
| def create_kv(secret, secret_json, content_def): | def create_kv(logger, id, secret, secret_json, content_def): | ||||||
|     secret.type = "Opaque" |  | ||||||
|     secret.data = {} |     secret.data = {} | ||||||
|     for eleml in content_def: |     for eleml in content_def: | ||||||
|         for k, elem in eleml.items(): |         for k, elem in eleml.items(): | ||||||
| @@ -31,6 +30,13 @@ def create_kv(secret, secret_json, content_def): | |||||||
|                         f"Field {_secret_key} has no value in bitwarden secret") |                         f"Field {_secret_key} has no value in bitwarden secret") | ||||||
|                 secret.data[_secret_ref] = str(base64.b64encode( |                 secret.data[_secret_ref] = str(base64.b64encode( | ||||||
|                     value.encode("utf-8")), "utf-8") |                     value.encode("utf-8")), "utf-8") | ||||||
|  |             if _secret_scope == "attachment": | ||||||
|  |                 value = get_attachment(logger, id, _secret_key) | ||||||
|  |                 if value is None: | ||||||
|  |                     raise Exception( | ||||||
|  |                         f"Attachment {_secret_key} has no value in bitwarden secret") | ||||||
|  |                 secret.data[_secret_ref] = str(base64.b64encode( | ||||||
|  |                     value.encode("utf-8")), "utf-8") | ||||||
|     return secret |     return secret | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -42,6 +48,8 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | |||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|     labels = spec.get('labels') |     labels = spec.get('labels') | ||||||
|  |     custom_annotations = spec.get('annotations') | ||||||
|  |     custom_secret_type = spec.get('secretType') | ||||||
|  |  | ||||||
|     unlock_bw(logger) |     unlock_bw(logger) | ||||||
|     logger.info(f"Locking up secret with ID: {id}") |     logger.info(f"Locking up secret with ID: {id}") | ||||||
| @@ -54,13 +62,25 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | |||||||
|         "managedObject": f"{namespace}/{name}" |         "managedObject": f"{namespace}/{name}" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if custom_annotations: | ||||||
|  |         annotations.update(custom_annotations) | ||||||
|  |  | ||||||
|  |     if not custom_secret_type: | ||||||
|  |         custom_secret_type = 'Opaque' | ||||||
|  |  | ||||||
|     if not labels: |     if not labels: | ||||||
|         labels = {} |         labels = {} | ||||||
|  |  | ||||||
|     secret = kubernetes.client.V1Secret() |     secret = kubernetes.client.V1Secret() | ||||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( |     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||||
|         name=secret_name, annotations=annotations, labels=labels) |         name=secret_name, annotations=annotations, labels=labels) | ||||||
|     secret = create_kv(secret, secret_json_object, content_def) |     secret.type = custom_secret_type | ||||||
|  |     secret = create_kv(logger, id, secret, secret_json_object, content_def) | ||||||
|  |  | ||||||
|  |     # Garbage collection will delete the generated secret if the owner | ||||||
|  |     # Is not in the same namespace as the generated secret | ||||||
|  |     if secret_namespace == namespace: | ||||||
|  |         kopf.append_owner_reference(secret) | ||||||
|  |  | ||||||
|     api.create_namespaced_secret( |     api.create_namespaced_secret( | ||||||
|         namespace="{}".format(secret_namespace), |         namespace="{}".format(secret_namespace), | ||||||
| @@ -86,19 +106,27 @@ def update_managed_secret( | |||||||
|     old_config = None |     old_config = None | ||||||
|     old_secret_name = None |     old_secret_name = None | ||||||
|     old_secret_namespace = None |     old_secret_namespace = None | ||||||
|  |     old_secret_type = None | ||||||
|     if 'kopf.zalando.org/last-handled-configuration' in body.metadata.annotations: |     if 'kopf.zalando.org/last-handled-configuration' in body.metadata.annotations: | ||||||
|         old_config = json.loads( |         old_config = json.loads( | ||||||
|             body.metadata.annotations['kopf.zalando.org/last-handled-configuration']) |             body.metadata.annotations['kopf.zalando.org/last-handled-configuration']) | ||||||
|         old_secret_name = old_config['spec'].get('name') |         old_secret_name = old_config['spec'].get('name') | ||||||
|         old_secret_namespace = old_config['spec'].get('namespace') |         old_secret_namespace = old_config['spec'].get('namespace') | ||||||
|  |         old_secret_type = old_config['spec'].get('type') | ||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|  |     labels = spec.get('labels') | ||||||
|  |     custom_annotations = spec.get('annotations') | ||||||
|  |     custom_secret_type = spec.get('secretType') | ||||||
|  |  | ||||||
|  |     if not custom_secret_type: | ||||||
|  |         custom_secret_type = 'Opaque' | ||||||
|  |  | ||||||
|     if old_config is not None and ( |     if old_config is not None and ( | ||||||
|             old_secret_name != secret_name or old_secret_namespace != secret_namespace): |             old_secret_name != secret_name or old_secret_namespace != secret_namespace or old_secret_type != custom_secret_type): | ||||||
|         # If the name of the secret or the namespace of the secret is different |         # If the name of the secret or the namespace of the secret is different | ||||||
|         # We have to delete the secret an recreate it |         # We have to delete the secret an recreate it | ||||||
|         logger.info("Secret name or namespace changed, let's recreate it") |         logger.info("Secret name, namespace or type changed, let's recreate it") | ||||||
|         delete_managed_secret( |         delete_managed_secret( | ||||||
|             old_config['spec'], |             old_config['spec'], | ||||||
|             name, |             name, | ||||||
| @@ -119,21 +147,36 @@ def update_managed_secret( | |||||||
|         "managedObject": f"{namespace}/{name}" |         "managedObject": f"{namespace}/{name}" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if custom_annotations: | ||||||
|  |         annotations.update(custom_annotations) | ||||||
|  |  | ||||||
|  |     if not labels: | ||||||
|  |         labels = {} | ||||||
|  |  | ||||||
|     secret = kubernetes.client.V1Secret() |     secret = kubernetes.client.V1Secret() | ||||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( |     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||||
|         name=secret_name, annotations=annotations) |         name=secret_name, annotations=annotations, labels=labels) | ||||||
|     secret = create_kv(secret, secret_json_object, content_def) |     secret.type = custom_secret_type | ||||||
|  |     secret = create_kv(logger, id, secret, secret_json_object, content_def) | ||||||
|  |  | ||||||
|  |     # Garbage collection will delete the generated secret if the owner | ||||||
|  |     # Is not in the same namespace as the generated secret | ||||||
|  |     if secret_namespace == namespace: | ||||||
|  |         kopf.append_owner_reference(secret) | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         obj = api.replace_namespaced_secret( |         api.replace_namespaced_secret( | ||||||
|             name=secret_name, |             name=secret_name, | ||||||
|             body=secret, |             body=secret, | ||||||
|             namespace="{}".format(secret_namespace)) |             namespace="{}".format(secret_namespace)) | ||||||
|         logger.info( |         logger.info( | ||||||
|             f"Secret {secret_namespace}/{secret_name} has been updated") |             f"Secret {secret_namespace}/{secret_name} has been updated") | ||||||
|     except BaseException: |     except BaseException as e: | ||||||
|         logger.warn( |         logger.warn( | ||||||
|             f"Could not update secret {secret_namespace}/{secret_name}!") |             f"Could not update secret {secret_namespace}/{secret_name}!") | ||||||
|  |         logger.warn( | ||||||
|  |             f"Exception: {e}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @kopf.on.delete('bitwarden-secret.lerentis.uploadfilter24.eu') | @kopf.on.delete('bitwarden-secret.lerentis.uploadfilter24.eu') | ||||||
|   | |||||||
| @@ -17,7 +17,6 @@ def render_template(logger, template): | |||||||
|  |  | ||||||
|  |  | ||||||
| def create_template_secret(logger, secret, filename, template): | def create_template_secret(logger, secret, filename, template): | ||||||
|     secret.type = "Opaque" |  | ||||||
|     secret.data = {} |     secret.data = {} | ||||||
|     secret.data[filename] = str( |     secret.data[filename] = str( | ||||||
|         base64.b64encode( |         base64.b64encode( | ||||||
| @@ -34,6 +33,8 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | |||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|     labels = spec.get('labels') |     labels = spec.get('labels') | ||||||
|  |     custom_annotations = spec.get('annotations') | ||||||
|  |     custom_secret_type = spec.get('secretType') | ||||||
|  |  | ||||||
|     unlock_bw(logger) |     unlock_bw(logger) | ||||||
|  |  | ||||||
| @@ -44,15 +45,27 @@ def create_managed_secret(spec, name, namespace, logger, body, **kwargs): | |||||||
|         "managedObject": f"{namespace}/{name}" |         "managedObject": f"{namespace}/{name}" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if custom_annotations: | ||||||
|  |         annotations.update(custom_annotations) | ||||||
|  |  | ||||||
|  |     if not custom_secret_type: | ||||||
|  |         custom_secret_type = 'Opaque' | ||||||
|  |  | ||||||
|     if not labels: |     if not labels: | ||||||
|         labels = {} |         labels = {} | ||||||
|  |  | ||||||
|     secret = kubernetes.client.V1Secret() |     secret = kubernetes.client.V1Secret() | ||||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( |     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||||
|         name=secret_name, annotations=annotations, labels=labels) |         name=secret_name, annotations=annotations, labels=labels) | ||||||
|  |     secret.type = custom_secret_type | ||||||
|     secret = create_template_secret(logger, secret, filename, template) |     secret = create_template_secret(logger, secret, filename, template) | ||||||
|  |  | ||||||
|     obj = api.create_namespaced_secret( |     # Garbage collection will delete the generated secret if the owner | ||||||
|  |     # Is not in the same namespace as the generated secret | ||||||
|  |     if secret_namespace == namespace: | ||||||
|  |         kopf.append_owner_reference(secret) | ||||||
|  |  | ||||||
|  |     api.create_namespaced_secret( | ||||||
|         secret_namespace, secret |         secret_namespace, secret | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
| @@ -74,20 +87,28 @@ def update_managed_secret( | |||||||
|     filename = spec.get('filename') |     filename = spec.get('filename') | ||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|  |     labels = spec.get('labels') | ||||||
|  |     custom_annotations = spec.get('annotations') | ||||||
|  |     custom_secret_type = spec.get('secretType') | ||||||
|  |  | ||||||
|  |     if not custom_secret_type: | ||||||
|  |         custom_secret_type = 'Opaque' | ||||||
|  |  | ||||||
|     old_config = None |     old_config = None | ||||||
|     old_secret_name = None |     old_secret_name = None | ||||||
|     old_secret_namespace = None |     old_secret_namespace = None | ||||||
|  |     old_secret_type = None | ||||||
|     if 'kopf.zalando.org/last-handled-configuration' in body.metadata.annotations: |     if 'kopf.zalando.org/last-handled-configuration' in body.metadata.annotations: | ||||||
|         old_config = json.loads( |         old_config = json.loads( | ||||||
|             body.metadata.annotations['kopf.zalando.org/last-handled-configuration']) |             body.metadata.annotations['kopf.zalando.org/last-handled-configuration']) | ||||||
|         old_secret_name = old_config['spec'].get('name') |         old_secret_name = old_config['spec'].get('name') | ||||||
|         old_secret_namespace = old_config['spec'].get('namespace') |         old_secret_namespace = old_config['spec'].get('namespace') | ||||||
|  |         old_secret_type = old_config['spec'].get('type') | ||||||
|     secret_name = spec.get('name') |     secret_name = spec.get('name') | ||||||
|     secret_namespace = spec.get('namespace') |     secret_namespace = spec.get('namespace') | ||||||
|  |  | ||||||
|     if old_config is not None and ( |     if old_config is not None and ( | ||||||
|             old_secret_name != secret_name or old_secret_namespace != secret_namespace): |             old_secret_name != secret_name or old_secret_namespace != secret_namespace or old_secret_type != custom_secret_type): | ||||||
|         # If the name of the secret or the namespace of the secret is different |         # If the name of the secret or the namespace of the secret is different | ||||||
|         # We have to delete the secret an recreate it |         # We have to delete the secret an recreate it | ||||||
|         logger.info("Secret name or namespace changed, let's recreate it") |         logger.info("Secret name or namespace changed, let's recreate it") | ||||||
| @@ -108,21 +129,37 @@ def update_managed_secret( | |||||||
|         "managed": "bitwarden-template.lerentis.uploadfilter24.eu", |         "managed": "bitwarden-template.lerentis.uploadfilter24.eu", | ||||||
|         "managedObject": f"{namespace}/{name}" |         "managedObject": f"{namespace}/{name}" | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if custom_annotations: | ||||||
|  |         annotations.update(custom_annotations) | ||||||
|  |  | ||||||
|  |     if not labels: | ||||||
|  |         labels = {} | ||||||
|  |  | ||||||
|     secret = kubernetes.client.V1Secret() |     secret = kubernetes.client.V1Secret() | ||||||
|     secret.metadata = kubernetes.client.V1ObjectMeta( |     secret.metadata = kubernetes.client.V1ObjectMeta( | ||||||
|         name=secret_name, annotations=annotations) |         name=secret_name, annotations=annotations, labels=labels) | ||||||
|  |     secret.type = custom_secret_type | ||||||
|     secret = create_template_secret(logger, secret, filename, template) |     secret = create_template_secret(logger, secret, filename, template) | ||||||
|  |  | ||||||
|  |     # Garbage collection will delete the generated secret if the owner | ||||||
|  |     # Is not in the same namespace as the generated secret | ||||||
|  |     if secret_namespace == namespace: | ||||||
|  |         kopf.append_owner_reference(secret) | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         obj = api.replace_namespaced_secret( |         api.replace_namespaced_secret( | ||||||
|             name=secret_name, |             name=secret_name, | ||||||
|             body=secret, |             body=secret, | ||||||
|             namespace="{}".format(secret_namespace)) |             namespace="{}".format(secret_namespace)) | ||||||
|         logger.info( |         logger.info( | ||||||
|             f"Secret {secret_namespace}/{secret_name} has been updated") |             f"Secret {secret_namespace}/{secret_name} has been updated") | ||||||
|     except BaseException: |     except BaseException as e: | ||||||
|         logger.warn( |         logger.warn( | ||||||
|             f"Could not update secret {secret_namespace}/{secret_name}!") |             f"Could not update secret {secret_namespace}/{secret_name}!") | ||||||
|  |         logger.warn( | ||||||
|  |             f"Exception: {e}" | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @kopf.on.delete('bitwarden-template.lerentis.uploadfilter24.eu') | @kopf.on.delete('bitwarden-template.lerentis.uploadfilter24.eu') | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user