-
Notifications
You must be signed in to change notification settings - Fork 3
/
populate-secrets-from-bitwarden.sh
executable file
·294 lines (241 loc) · 13.5 KB
/
populate-secrets-from-bitwarden.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#!/bin/bash
set -o errexit
set -o nounset
set -o pipefail
# This script uses a connection to Bitwarden to populate k8s secrets used for
# the cluster. To use this script, first get the BitWarden CLI at:
# https://help.bitwarden.com/article/cli/#download--install
# Then, log in to create a session:
# $ BW_SESSION="$( bw login username@company.com password --raw )"
# Pass that environment variable to this script so that it can use the session.
#
# WARNING: BitWarden sessions are sticky -- if changes have occurred to the
# content of the BitWarden vault after your current session was started,
# you will need to create a new session to be able to view those changes.
OC_STATUS=$(oc status | grep "on server ")
readonly OC_STATUS
OC_PROJECT=$(echo ${OC_STATUS} | awk '{print $3}')
readonly OC_PROJECT
OC_CLUSTER=$(echo ${OC_STATUS} | awk '{print $NF}')
readonly OC_CLUSTER
OC_USER=$(oc whoami)
readonly OC_USER
if [[ "${OC_CLUSTER}" != "https://api.devint.openshiftknativedemo.org:6443" ]]; then
>&2 echo "[ERROR] current cluster ${OC_CLUSTER} is not our devint cluster ... please run 'oc login https://api.devint.openshiftknativedemo.org:6443' first!"
exit 1
fi
if [[ "${OC_PROJECT}" != "ci" ]]; then
>&2 echo "[WARNING] current project ${OC_PROJECT} is not 'ci'!"
fi
if ! oc auth can-i create secrets -n "${OC_PROJECT}" --quiet; then
>&2 echo "[ERROR] current user ${OC_USER} does not have permission to create secret in ${OC_PROJECT}"
exit 1
fi
if [[ -z "${BW_SESSION:-}" ]]; then
>&2 echo "[ERROR] Ensure you have an active BitWarden session and provide the session token with \$BW_SESSION"
exit 1
fi
# Fetching attachments saves files locally
# that we need to track and clean up. Also,
# we're making a local copy of all of the
# secrets for faster processing, so we need
# to clean that up, too
work_dir="$( mktemp -d )"
cd "${work_dir}"
function cleanup() {
rm -rf "${work_dir}"
}
trap cleanup EXIT
# BitWarden's `get item $name` invocation does a search on
# the data stored in every secret, so secrets with names
# that are similar to fields in other secrets will not be
# addressable. There is also no way to specifically target
# the item's name field for searching. Therefore, we need
# to dump the list of secrets and search through it explicitly
# using jq. Thankfully, that's not too hard.
secrets="${work_dir}/secrets.json"
bw --session "${BW_SESSION}" list items > "${secrets}"
if [[ "$( jq ". | length" <"${secrets}" )" == 0 ]]; then
echo "[WARNING] Your active BitWarden session does not have access to secrets. If you created your session before you got access, refresh it by logging out and in again."
exit 1
fi
# retrieve the value of a top-level field from an item in BitWarden
# and format it in a key-value pair for a k8s secret
function format_field() {
local item="$1"
local field="$2"
local name="${3:-"${item}"}"
echo "--from-literal=${name}=$( jq ".[] | select(.name == \"${item}\") | ${field}" --raw-output <"${secrets}" )"
}
# retrieve the value of a field from an item in BitWarden
function get_field_value() {
local item="$1"
local field="$2"
jq ".[] | select(.name == \"${item}\") | .fields[] | select(.name == \"${field}\") | .value" --raw-output <"${secrets}"
}
# retrieve the value of a field from an item in BitWarden
# and format it in a key-value pair for a k8s secret
function format_field_value() {
local item="$1"
local field="$2"
local name="${3:-"${item}"}"
echo "--from-literal=${name}=$(get_field_value "${item}" "${field}")"
}
# retrieve the content of an attachment from an item in BitWarden
function get_attachment() {
local item="$1"
local attachment="$2"
local item_id="$( jq ".[] | select(.name == \"${item}\") | .id" --raw-output <"${secrets}" )"
local attachment_id="$( jq ".[] | select(.name == \"${item}\") | .attachments[] | select(.fileName == \"${attachment}\") | .id" --raw-output <"${secrets}" )"
bw --session "${BW_SESSION}" get attachment "${attachment_id}" --itemid "${item_id}" --raw
}
# retrieve the content of an attachment from an item in BitWarden
# and format it in a key-value pair for a k8s secret
function format_attachment() {
local item="$1"
local attachment="$2"
local name="${3:-"${attachment}"}"
echo "--from-file=${name}=$(get_attachment "${item}" "${attachment}")"
}
function update_secret() {
local name
name=$2
oc create secret "$@" --dry-run -o yaml | oc apply -f -
oc label secret --overwrite "${name}" "ci.openshift.io/managed=true"
}
# retrieve the value of a field and format it as a string, for
# use when more complex values are required to generate a secret
function field_value() {
local item="$1"
local field="$2"
echo "$( jq ".[] | select(.name == \"${item}\") | .fields[] | select(.name == \"${field}\") | .value" --raw-output <"${secrets}")"
}
oc project openshift-config
update_secret generic "github-oauth-secret" "$( format_field_value "github-oauth-secret" "clientSecret" "clientSecret" )"
exit 0
## Examples below left for reference but are not used
# Bugzilla API keys are stored as a text field named "API Key"
login="openshift-bugzilla-robot"
update_secret generic "bugzilla-credentials-${login}" "$( format_field_value "${login}" "API Key" "api" )"
# Jenkins credentials are stored as separate items in Bitwarden,
# with the token recorded as the password for the account
for master in "ci.openshift.redhat.com" "kata-jenkins-ci.westus2.cloudapp.azure.com"; do
update_secret generic "jenkins-credentials-${master}" "$( format_field "${master}" ".login.password" "password" )"
done
# Client certificates for the ci.dev Jenkins
# master are stored in a special set of fields
master="ci.dev.openshift.redhat.com"
update_secret generic "jenkins-credentials-${master}" \
"$( format_field "${master}" ".login.password" "password" )" \
"$( format_attachment "${master}" cert.pem )" \
"$( format_attachment "${master}" key.pem )" \
"$( format_attachment "${master}" ca.pem )"
# OAuth tokens for GitHub are stored as a text field named
# "GitHub OAuth Token" on login credential items for each robot.
for login in "openshift-bot" "openshift-build-robot" "openshift-cherrypick-robot" "openshift-ci-robot" "openshift-merge-robot" "openshift-publish-robot"; do
update_secret generic "github-credentials-${login}" "$( format_field_value "${login}" "GitHub OAuth Token" "oauth" )"
done
# openshift-publish-robot also has a token that grants read-only
# access to private repositories.
update_secret generic "private-git-cloner" "$( format_field_value "openshift-publish-robot" private-git-cloner "oauth" )"
# Configuration for Slack ci-chat-bot is stored under "Token"
# and the key value is "token" in the secret
update_secret generic ci-chat-bot-slack-token "$( format_field_value ci-chat-bot-slack-token "Token" "token" )"
# Configuration for api_url, which is for slack incoming hooks and can be used eg in prometheus alert-manager, is stored under "url"
# and the key value is "url" in the secret
update_secret generic ci-slack-api-url "$( format_field_value ci-slack-api-url "url" "url" )"
# Configuration for GitHub OAuth Apps are stored
# as an opaque field "Client Configuration"
update_secret generic github-app-credentials "$( format_field_value prow.svc.ci.openshift.org "Client Configuration" "config.json" )"
# Cookie secret to encrypt frontend and backend
# communication is stored in the "Cookie" field
update_secret generic cookie "$( format_field_value prow.svc.ci.openshift.org Cookie "cookie" )"
# HMAC token for encrypting GitHub webhook payloads
# is stored in the "HMAC Token" field
update_secret generic github-webhook-credentials "$( format_field_value hmac "HMAC Token" "hmac" )"
# DeploymentConfig token is used to auth trigger events
# for DeploymentConfigs from GitHub
update_secret generic github-deploymentconfig-trigger "$( format_field_value github-deploymentconfig-webhook-token "Token" "WebHookSecretKey" )"
# Credentials for GCE service accounts are stored
# as an attachment on each distinct credential
for account in "aos-pubsub-subscriber" "ci-vm-operator" "gcs-publisher" "gcs-tide-publisher"; do
update_secret generic "gce-sa-credentials-${account}" "$( format_attachment "${account}" credentials.json service-account.json )"
done
# Some GCE serviceaccounts also have SSH keys
for account in "aos-serviceaccount" "jenkins-ci-provisioner"; do
update_secret generic "gce-sa-credentials-${account}" \
"$( format_attachment "${account}" credentials.json service-account.json )" \
"$( format_attachment "${account}" ssh-privatekey )" \
"$( format_attachment "${account}" ssh-publickey )"
done
# Credentials for registries are stored as
# separate fields on individual items
for registry in "docker.io" "quay.io" "quay.io/openshift-knative" "quay.io/openshiftio" "quay.io/openshift-pipeline" "quay.io/codeready-toolchain" "quay.io/operator-manifests"; do
update_secret generic "registry-push-credentials-${registry//\//\-}" $( format_field_value "${registry}" "Push Credentials" "config.json" )
# we want to be able to build and push out to registries
oc secrets link builder "registry-push-credentials-${registry//\//\-}"
done
registry="quay.io"
update_secret generic "registry-pull-credentials-${registry}" $( format_field_value "${registry}" "Pull Credentials" "config.json" )
update_secret generic "ci-pull-credentials" --type=kubernetes.io/dockerconfigjson $( format_field_value "${registry}" "Pull Credentials" ".dockerconfigjson" )
update_secret generic "operator-manifests-test-credentials" \
"$( format_attachment "operator-manifests" test.env.yaml )" \
"$( format_attachment "operator-manifests" quay-env.txt )"
# Cluster credentials aggregate multiple items
# of information for easy consumption by tests
target_cloud="aws"
update_secret generic "cluster-secrets-${target_cloud}" \
"$( format_attachment "quay.io" pull-secret )" \
"$( format_attachment "insights-ci-account" insights-live.yaml )" \
"$( format_attachment "jenkins-ci-iam" .awscred )" \
"$( format_attachment "jenkins-ci-iam" ssh-privatekey )" \
"$( format_attachment "mirror.openshift.com" cert-key.pem ops-mirror.pem )" \
"$( format_attachment "jenkins-ci-iam" ssh-publickey )"
target_cloud="gcp"
update_secret generic "cluster-secrets-${target_cloud}" \
"$( format_attachment "quay.io" pull-secret )" \
"$( format_attachment "insights-ci-account" insights-live.yaml )" \
"$( format_attachment "jenkins-ci-provisioner" credentials.json gce.json )" \
"$( format_attachment "jenkins-ci-provisioner" ssh-privatekey )" \
"$( format_attachment "jenkins-ci-provisioner" ssh-publickey )" \
"$( format_attachment "mirror.openshift.com" cert-key.pem ops-mirror.pem )" \
"$( format_field_value telemeter "Telemeter Token" "telemeter-token" )"
target_cloud="openstack"
update_secret generic "cluster-secrets-${target_cloud}" \
"$( format_attachment "quay.io" pull-secret )" \
"$( format_attachment "openstack" clouds.yaml )" \
"$( format_attachment "insights-ci-account" insights-live.yaml )" \
"$( format_attachment "jenkins-ci-provisioner" ssh-privatekey )" \
"$( format_attachment "jenkins-ci-provisioner" ssh-publickey )"
target_cloud="vsphere"
update_secret generic "cluster-secrets-${target_cloud}" \
"$( format_attachment "quay.io" pull-secret )" \
"$( format_attachment "insights-ci-account" insights-live.yaml )" \
"$( format_attachment "jenkins-ci-iam" .awscred )" \
"$( format_attachment "jenkins-ci-iam" ssh-privatekey )" \
"$( format_attachment "jenkins-ci-iam" ssh-publickey )" \
"$( format_attachment "vsphere-credentials" secret.auto.tfvars )"
target_cloud="metal"
update_secret generic "cluster-secrets-${target_cloud}" \
"$( format_attachment "quay.io" pull-secret )" \
"$( format_attachment "insights-ci-account" insights-live.yaml )" \
"$( format_attachment "jenkins-ci-iam" .awscred )" \
"$( format_attachment "jenkins-ci-iam" ssh-privatekey )" \
"$( format_attachment "jenkins-ci-iam" ssh-publickey )" \
"$( format_attachment "packet.net" .packetcred )" \
"$( format_attachment "packet.net" client.crt matchbox-client.crt )" \
"$( format_attachment "packet.net" client.key matchbox-client.key )"
target_cloud="azure"
update_secret generic "cluster-secrets-${target_cloud}" \
"$( format_attachment "quay.io" pull-secret )" \
"$( format_attachment "os4-installer.openshift-ci.azure" osServicePrincipal.json )" \
"$( format_attachment "jenkins-ci-iam" ssh-privatekey )" \
"$( format_attachment "jenkins-ci-iam" ssh-publickey )"
# DSNs for tools reporting failures to Sentry
update_secret generic "sentry-dsn" "$( format_field_value "sentry" "ci-operator" "ci-operator" )"
# codecov.io tokens we store for teams
update_secret generic "redhat-developer-service-binding-operator-codecov-token" "$( format_field_value "codecov-tokens" redhat-developer-service-binding-operator token )"
# Configuration for the .git-credentials used by the release controller to clone
# private repositories to generate changelogs
oc -n "ci-release" create secret generic "git-credentials" "--from-literal=.git-credentials=https://openshift-bot:$( field_value "openshift-bot" "GitHub OAuth Token" "oauth" )@github.com" --dry-run -o yaml | oc apply -f -
oc -n "ci-release" label secret "git-credentials" "ci.openshift.io/managed=true" --overwrite