Skip to content

Commit d6a175c

Browse files
szhGitHub Enterprise
authored andcommitted
Merge pull request #6 from Conjur-Enterprise/export_api_key
CNJR-0000: Automatically generate an authentication token
2 parents 68a1c7e + baac13e commit d6a175c

File tree

10 files changed

+186
-3
lines changed

10 files changed

+186
-3
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## Unreleased
88

9-
## [2.0.8] - 2025-03-25
9+
## [2.1.0] - 2025-08-28
10+
11+
### Added
12+
13+
- The Conjur OSS Helm chart has been extended to optionally generate a short-lived authentication token (stored in a Kubernetes Secret) for the admin account
1014

1115
## [2.0.7] - 2023-08-30
1216

@@ -173,7 +177,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
173177
### Added
174178
- First version of chart available.
175179

176-
[Unreleased]: https://github.com/cyberark/conjur-oss-helm-chart/compare/v2.0.7...HEAD
180+
[2.1.0]: https://github.com/cyberark/conjur-oss-helm-chart/compare/v2.0.7...v2.1.0
177181
[2.0.7]: https://github.com/cyberark/conjur-oss-helm-chart/compare/v2.0.6...v2.0.7
178182
[2.0.6]: https://github.com/cyberark/conjur-oss-helm-chart/compare/v2.0.5...v2.0.6
179183
[2.0.5]: https://github.com/cyberark/conjur-oss-helm-chart/compare/v2.0.4...v2.0.5

conjur-oss/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Conjur Open Source is part of the CyberArk Privileged Access Security Solution w
2222
+ [Example: Installation Using Command Line Arguments](#example-installation-using-command-line-arguments)
2323
+ [Example: Installation Using Custom YAML File](#example-installation-using-custom-yaml-file)
2424
* [Configuring Conjur Accounts](#configuring-conjur-accounts)
25+
+ [Accessing account credentials via a Kubernetes Secret](#accessing-account-credentials-via-a-kubernetes-secret)
2526
* [Installing Conjur with an External Postgres Database](#installing-conjur-with-an-external-postgres-database)
2627
* [Auto-Generated Configuration](#auto-generated-configuration)
2728
- [Upgrading, Modifying, or Migrating a Conjur Open Source Helm Deployment](#upgrading-modifying-or-migrating-a-conjur-open-source-helm-deployment)
@@ -257,9 +258,16 @@ kubectl exec --namespace $CONJUR_NAMESPACE \
257258
--container=conjur-oss \
258259
-- conjurctl account create $CONJUR_ACCOUNT | tail -1
259260
```
261+
260262
The credentials for this account will be provided after the account has been created.
261263
Store these in a safe location.
262264

265+
#### Accessing account credentials via a Kubernetes Secret
266+
267+
This chart includes the ability to automatically generate a short-lived token that can be used to programmatically authenticate to the Conjur service. The token is stored as a json file (token.json) in a Secret (`conjur-oss-conjur-admin-token`) in the same namespace as the Conjur service. The main use-case for this feature is to enable full automation of bootstrapping Conjur with initial policies, i.e. ones that provide further authenticators and hosts. For example, Conjur's Go SDK provides a method `NewClientFromTokenFile` which accepts the token.json file.
268+
269+
_**NOTE:**_ Be aware that this token is for the admin account created when the Conjur service first starts and, thus, has full privileges over the service. It is intended to enable the Conjur service to be bootstrapped with further, less privileged authenticators and hosts. With this in mind the token, by default, expires 10 minutes after being created. Although this value can be increased we recommend that you do not.
270+
263271
### Installing Conjur with an External Postgres Database
264272

265273
You can configure Conjur to use an external (non-integrated) Postgres database
@@ -398,6 +406,12 @@ The following table lists the configurable parameters of the Conjur Open Source
398406
|`ssl.expiration`|Expiration limit for generated certificates|`365`|
399407
|`ssl.hostname`|Hostname and Common Name for generated certificate and ingress|`"conjur.myorg.com"`|
400408
|`postgresLabels`|Extra Kubernetes labels to apply to Conjur PostgreSQL resources|`{}`|
409+
|`exportAPIkey.enabled`|Controls whether a json authentication token should be created for the Conjur account specified in `account.name` and stored in a Kubernetes Secret. _**NOTE:**_ if you set this value to true you must also set `account.create` to `true`|`false`|
410+
|`exportAPIkey.secretName`|Name of the Secret to store the authentication token (in a file called token.json)|`"conjur-oss-conjur-admin-token"`|
411+
|`exportAPIkey.ttl`|How long the token will remain valid (use a valid `date -d` value, e.g. 15 minutes, 1 day)|"10 minutes"|
412+
|`exportAPIkey.image.repository`|Image used for the container which executes the script [export.sh](./files/export.sh) to generate the token|`registry.gitlab.com/gitlab-ci-utils/curl-jq`|
413+
|`exportAPIkey.image.tag`|Image tag|`"3.2.1"`|
414+
|`exportAPIkey.image.pullPolicy`|Image pull policy|`Always`|
401415

402416
### Deploying Without Persistent Volume Support (e.g. for MiniKube, KataCoda)
403417
Some Kubernetes platforms (e.g. MiniKube and KataCoda) do not have
@@ -560,6 +574,7 @@ The Kubernetes secrets that may need to be manually deleted following
560574
|`<helm-release>-conjur-data-key`|Data encryption key|Always|
561575
|`<helm-release>-conjur-ssl-ca-cert`|Conjur SSL CA Certificate|When auto-generated (i.e. not explicitly set)|
562576
|`<helm-release>-conjur-ssl-cert`|Conjur SSL Access Certificate|When auto-generated (i.e. not explicitly set)|
577+
|`<helm-release>-conjur-admin-token`|Authentication token for Conjur|If `exportAPIkey.enabled` set to `true`|
563578

564579
To delete the residual "self-managed" Kubernetes secrets associated with
565580
the Conjur deployment, run the following:

conjur-oss/files/export.sh

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/bin/bash
2+
3+
echo "Sidecar: Waiting for main application's HTTP endpoint at http://localhost:8080/..."
4+
5+
while ! curl --fail-with-body --silent --output /dev/null http://localhost:8080/; do
6+
echo "Sidecar: Main application HTTP endpoint not ready yet, sleeping..."
7+
sleep 10
8+
done
9+
echo "Sidecar: Main application HTTP endpoint is ready!"
10+
11+
TOKEN_EXPIRATION=$(date -d "now + {{ .Values.exportAPIkey.ttl }}" +%s)
12+
TOKEN_VALUE=$(echo "{\"account\":\"${CONJUR_ACCOUNT}\", \"sub\":\"admin\", \"exp\":$TOKEN_EXPIRATION}" | socat - UNIX-CONNECT:"/run/authn-local/.socket")
13+
echo "Sidecar: Generated Conjur token value"
14+
15+
echo "Sidecar: Proceeding to create Kubernetes Secret using curl..."
16+
17+
# Kubernetes API access details (provided by the ServiceAccount mount)
18+
SERVICEACCOUNT_DIR="/var/run/secrets/kubernetes.io/serviceaccount"
19+
TOKEN=$(cat "${SERVICEACCOUNT_DIR}/token")
20+
NAMESPACE=$(cat "${SERVICEACCOUNT_DIR}/namespace")
21+
CACERT="${SERVICEACCOUNT_DIR}/ca.crt"
22+
KUBERNETES_SERVICE_HOST=$KUBERNETES_SERVICE_HOST # Injected by Kubernetes
23+
KUBERNETES_SERVICE_PORT=$KUBERNETES_SERVICE_PORT # Injected by Kubernetes
24+
25+
API_SERVER_URL="https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}"
26+
SECRETS_API_PATH="/api/v1/namespaces/${NAMESPACE}/secrets"
27+
28+
SECRET_NAME="{{ .Values.exportAPIkey.secretName }}"
29+
SECRET_KEY="token.json"
30+
31+
# Base64 encode the secret value
32+
# Using tr -d '\n' to remove newline characters added by base64 on some systems
33+
ENCODED_VALUE=$(echo -n "${TOKEN_VALUE}" | base64 | tr -d '\n')
34+
35+
# Construct the JSON payload for the Secret
36+
read -r -d '' JSON_PAYLOAD <<EOF
37+
{
38+
"apiVersion": "v1",
39+
"kind": "Secret",
40+
"metadata": {
41+
"name": "${SECRET_NAME}"
42+
},
43+
"type": "Opaque",
44+
"data": {
45+
"${SECRET_KEY}": "${ENCODED_VALUE}"
46+
}
47+
}
48+
EOF
49+
50+
echo "Sidecar: removing any existing Secret with the same name..."
51+
curl -X DELETE \
52+
-H "Authorization: Bearer ${TOKEN}" \
53+
--cacert "${CACERT}" \
54+
--silent \
55+
--output /dev/null \
56+
--write-out "%{http_code}\n" \
57+
"${API_SERVER_URL}${SECRETS_API_PATH}/${SECRET_NAME}" | grep -q "200" && echo "Sidecar: Successfully deleted existing Secret '$SECRET_NAME'." || echo "Sidecar: No existing Secret '$SECRET_NAME' to delete or deletion failed."
58+
59+
echo "Sidecar: Attempting to create Secret '$SECRET_NAME' in namespace '$NAMESPACE'..."
60+
HTTP_CODE=$(curl -X POST \
61+
-H "Authorization: Bearer ${TOKEN}" \
62+
--json "${JSON_PAYLOAD}" \
63+
--cacert "${CACERT}" \
64+
--silent \
65+
--output /dev/null \
66+
--write-out "%{http_code}\n" \
67+
"${API_SERVER_URL}${SECRETS_API_PATH}")
68+
69+
if [[ "$HTTP_CODE" =~ ^2 ]]; then # Check for 2xx success codes
70+
echo "Sidecar: Successfully created Secret '$SECRET_NAME'. HTTP Status: $HTTP_CODE"
71+
elif [[ "$HTTP_CODE" == "409" ]]; then # 409 Conflict means it already exists
72+
echo "Sidecar: Secret '$SECRET_NAME' already exists. HTTP Status: $HTTP_CODE"
73+
else
74+
echo "Sidecar: Failed to create Secret '$SECRET_NAME'. HTTP Status: $HTTP_CODE"
75+
fi
76+
77+
echo "Sidecar: Post-main-app-startup tasks completed."
78+
79+
# Keep the sidecar container running indefinitely to prevent it from exiting and causing
80+
# the control plane to try and restart it.
81+
tail -f /dev/null

conjur-oss/templates/auth-role.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ rules:
4242
- apiGroups: [""]
4343
resources: ["pods/exec"]
4444
verbs: ["create", "get"]
45+
{{- if .Values.exportAPIkey.enabled }}
46+
- apiGroups: [""]
47+
resources: ["secrets"]
48+
verbs: ["create", "delete", "update", "get", "list"]
49+
{{- end }}
4550
---
4651
kind: ClusterRoleBinding
4752
apiVersion: {{ include "conjur-oss.rbac-api" . }}

conjur-oss/templates/deployment.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ spec:
5555
- key: conjur_site
5656
path: sites-enabled/conjur.conf
5757
{{- end }}
58+
{{- if .Values.exportAPIkey.enabled }}
59+
- name: {{ .Release.Name }}-authn-local-socket-volume
60+
emptyDir: {}
61+
- name: {{ .Release.Name }}-export-api-key-configmap-volume
62+
configMap:
63+
name: {{ .Release.Name }}-export-api-key-configmap
64+
defaultMode: 0500
65+
{{- end }}
5866
containers:
5967
- name: {{ .Release.Name }}-nginx
6068
image: "{{ .Values.nginx.image.repository }}:{{ .Values.nginx.image.tag }}"
@@ -160,8 +168,33 @@ spec:
160168
value: {{ .Values.account.name }}
161169
- name: CONJUR_LOG_LEVEL
162170
value: {{ .Values.logLevel }}
171+
{{- if .Values.exportAPIkey.enabled }}
172+
volumeMounts:
173+
- name: {{ .Release.Name }}-authn-local-socket-volume
174+
mountPath: /run/authn-local
175+
readOnly: false
176+
{{- end }}
163177
resources:
164178
{{ toYaml .Values.resources | indent 12 }}
179+
{{- if .Values.exportAPIkey.enabled }}
180+
- name: {{ .Release.Name }}-export-api-key
181+
image: "{{ .Values.exportAPIkey.image.repository }}:{{ .Values.exportAPIkey.image.tag }}"
182+
imagePullPolicy: {{ .Values.exportAPIkey.image.pullPolicy }}
183+
command: [ "/bin/bash", "-c" ]
184+
args:
185+
- |
186+
apk add --no-cache socat
187+
/scripts/export.sh
188+
env:
189+
- name: CONJUR_ACCOUNT
190+
value: {{ .Values.account.name }}
191+
volumeMounts:
192+
- name: {{ .Release.Name }}-authn-local-socket-volume
193+
mountPath: /run/authn-local
194+
readOnly: false
195+
- name: {{ .Release.Name }}-export-api-key-configmap-volume
196+
mountPath: "/scripts"
197+
{{- end }}
165198
{{- with .Values.nodeSelector }}
166199
nodeSelector:
167200
{{ toYaml . | indent 8 }}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{{- if .Values.exportAPIkey.enabled }}
2+
apiVersion: v1
3+
kind: ConfigMap
4+
metadata:
5+
name: {{ .Release.Name }}-export-api-key-configmap
6+
namespace: {{ .Release.Namespace }}
7+
labels:
8+
chart: {{ template "conjur-oss.chart" . }}
9+
release: {{ .Release.Name }}
10+
heritage: {{ .Release.Service }}
11+
data:
12+
export.sh: {{ tpl (.Files.Get "files/export.sh") . | quote }}
13+
{{- end -}}

conjur-oss/templates/tests/test-simple-install-configmap.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ data:
77
@test "Testing that Conjur status page is up" {
88
curl -f --cacert /cacert/tls.crt https://{{ template "conjur-oss.fullname" . }}/ | grep 'Status'
99
}
10+
{{- if .Values.exportAPIkey.enabled }}
11+
@test "Testing that the Secret containing a Conjur authentication token has been created" {
12+
result=$(curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" "https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/api/v1/namespaces/$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)/secrets/{{ .Values.exportAPIkey.secretName }}" --output /dev/null --silent --write-out "%{http_code}")
13+
[ "$result" -eq 200 ]
14+
}
15+
{{- end }}

conjur-oss/templates/tests/test-simple-install.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ metadata:
1515
"helm.sh/hook-delete-policy": before-hook-creation
1616
{{ end }}
1717
spec:
18+
serviceAccountName: {{ template "conjur-oss.service-account" . }}
1819
initContainers:
1920
- name: {{ .Release.Name }}-bats-init
2021
image: bats/bats:v1.1

conjur-oss/values.schema.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,19 @@
250250
"type": "boolean"
251251
}
252252
}
253-
}
253+
},
254+
"exportAPIkey": {
255+
"properties": {
256+
"enabled": {
257+
"type": "boolean"
258+
},
259+
"secretName": {
260+
"type": "string"
261+
},
262+
"ttl": {
263+
"type": "string"
264+
}
265+
}
266+
}
254267
}
255268
}

conjur-oss/values.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,15 @@ tolerations: []
188188
# Set enabled true for OCP support
189189
openshift:
190190
enabled: false
191+
192+
# Set enabled to true to enable the Export API key feature.
193+
# This feature allows the Conjur server to export the API key for a given
194+
# Conjur user to a Kubernetes secret.
195+
exportAPIkey:
196+
enabled: false # If true, ensure account.create is also true.
197+
secretName: "conjur-oss-conjur-admin-token"
198+
ttl: "10 minutes"
199+
image:
200+
repository: registry.gitlab.com/gitlab-ci-utils/curl-jq
201+
tag: "3.2.1"
202+
pullPolicy: Always

0 commit comments

Comments
 (0)