This repository has been archived by the owner on Jan 25, 2023. It is now read-only.
/
run-vault
executable file
·398 lines (347 loc) · 11.2 KB
/
run-vault
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
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
#!/bin/bash
# This script is used to configure and run Vault on a Google Compute Instance.
set -e
readonly VAULT_CONFIG_FILE="default.hcl"
readonly SUPERVISOR_CONFIG_PATH="/etc/supervisor/conf.d/run-vault.conf"
readonly DEFAULT_PORT=8200
readonly DEFAULT_LOG_LEVEL="info"
readonly GCP_COMPUTE_INSTANCE_METADATA_URL="http://metadata.google.internal/computeMetadata/v1"
readonly GCP_METADATA_REQUEST_HEADER="Metadata-Flavor: Google"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"
function print_usage {
echo
echo "Usage: run-vault [OPTIONS]"
echo
echo "This script is used to configure and run Vault on a Google Compute Instance."
echo
echo "Required Arguments:"
echo
echo -e " --gcs-bucket\t\tThe name of the Google Cloud Storage Bucket where Vault data should be stored."
echo -e " --tls-cert-file\tSpecifies the path to the certificate for TLS. To use a CA certificate, concatenate"
echo -e " \tthe primary certificate and the CA certificate together."
echo -e " --tls-key-file\tSpecifies the path to the private key for the certificate."
echo
echo "Optional Arguments:"
echo
echo -e " --gcp-creds-file\tThe file path on the Compute Instance of a JSON file that stores credentials for a GCP"
echo -e " \tService Account that has read-write access to the configured GCS Bucket. If possible, leave"
echo -e " \tthis blank and obtain GCP resource permissions automatically via the default Service Account."
echo -e " --port\t\tThe port for Vault to listen on. Default is $DEFAULT_PORT."
echo -e " --cluster-port\tThe port for Vault to listen on for server-to-server requests. Default is --port + 1."
echo -e " --config-dir\t\tThe path to the Vault config folder. Default is the absolute path of '../config', relative to this script."
echo -e " --bin-dir\t\tThe path to the folder with Vault binary. Default is the absolute path of the parent folder of this script."
echo -e " --log-dir\t\tThe path to the Vault log folder. Default is the absolute path of '../log', relative to this script."
echo -e " --log-level\t\tThe log verbosity to use with Vault. Default is $DEFAULT_LOG_LEVEL."
echo -e " --user\t\tThe user to run Vault as. Default is to use the owner of --config-dir."
echo -e " --skip-vault-config\tIf this flag is set, don't generate a Vault configuration file. Default is false."
echo -e " --enable-ui\tIf this flag is set, the Vault UI will be enabled. Default is false."
echo
echo "Optional Arguments for enabling the GCP Cloud KMS seal:"
echo
echo -e " --enable-auto-unseal\tIf this flag is set, enable the GCP Cloud KMS Auto-unseal feature. This feature requires Vault Enterprise. Default is false."
echo -e " --auto-unseal-key-project-id\t"
echo -e " --auto-unseal-key-region\t"
echo -e " --auto-unseal-key-ring\t"
echo -e " --auto-unseal-crypto-key-name\t"
echo
echo "Example:"
echo
echo " run-vault --gcs-bucket my-vault-bucket --tls-cert-file /opt/vault/tls/vault.crt.pem --tls-key-file /opt/vault/tls/vault.key.pem"
echo
}
function log {
local readonly level="$1"
local readonly message="$2"
local readonly timestamp=$(date +"%Y-%m-%d %H:%M:%S")
>&2 echo -e "${timestamp} [${level}] [$SCRIPT_NAME] ${message}"
}
function log_info {
local readonly message="$1"
log "INFO" "$message"
}
function log_warn {
local readonly message="$1"
log "WARN" "$message"
}
function log_error {
local readonly message="$1"
log "ERROR" "$message"
}
# Based on code from: http://stackoverflow.com/a/16623897/483528
function strip_prefix {
local readonly str="$1"
local readonly prefix="$2"
echo "${str#$prefix}"
}
function assert_not_empty {
local readonly arg_name="$1"
local readonly arg_value="$2"
if [[ -z "$arg_value" ]]; then
log_error "The value for '$arg_name' cannot be empty"
print_usage
exit 1
fi
}
function assert_is_installed {
local readonly name="$1"
if [[ ! $(command -v ${name}) ]]; then
log_error "The binary '$name' is required by this script but is not installed or in the system's PATH."
exit 1
fi
}
# Get the value at a specific Instance Metadata path.
function get_instance_metadata_value {
local readonly path="$1"
log_info "Looking up Metadata value at $GCP_COMPUTE_INSTANCE_METADATA_URL/$path"
curl --silent --show-error --location --header "$GCP_METADATA_REQUEST_HEADER" "$GCP_COMPUTE_INSTANCE_METADATA_URL/$path"
}
# Get the IP Address of the current Compute Instance
function get_instance_ip_address {
local network_interface_number="$1"
# If no network interface number was specified, default to the first one
if [[ -z "$network_interface_number" ]]; then
network_interface_number=0
fi
log_info "Looking up Compute Instance IP Address on Network Interface $network_interface_number"
get_instance_metadata_value "instance/network-interfaces/$network_interface_number/ip"
}
function generate_vault_config {
local readonly tls_cert_file="$1"
local readonly tls_key_file="$2"
local readonly port="$3"
local readonly cluster_port="$4"
local readonly config_dir="$5"
local readonly user="$6"
local readonly gcs_bucket="$7"
local readonly gcp_creds_file="$8"
local readonly enable_auto_unseal="$9"
local readonly auto_unseal_project="${10}"
local readonly auto_unseal_region="${11}"
local readonly auto_unseal_key_ring="${12}"
local readonly auto_unseal_crypto_key="${13}"
local readonly enable_ui="${14}"
local readonly config_path="$config_dir/$VAULT_CONFIG_FILE"
local instance_ip_address
instance_ip_address=$(get_instance_ip_address)
if [[ "$enable_auto_unseal" == "true" ]]; then
log_info "Creating Vault gcpckms seal config file in $config_path"
cat > "$config_path" <<EOF
ui = $enable_ui
storage "gcs" {
bucket = "$gcs_bucket"
credentials_file = "$gcp_creds_file"
}
ha_storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
scheme = "http"
service = "vault"
}
seal "gcpckms" {
project = "$auto_unseal_project"
region = "$auto_unseal_region"
key_ring = "$auto_unseal_key_ring"
crypto_key = "$auto_unseal_crypto_key"
}
# HA settings
cluster_addr = "https://$instance_ip_address:$cluster_port"
api_addr = "https://$instance_ip_address:$port"
listener "tcp" {
address = "0.0.0.0:$port"
cluster_address = "0.0.0.0:$cluster_port"
tls_cert_file = "$tls_cert_file"
tls_key_file = "$tls_key_file"
}
EOF
else
log_info "Creating default Vault config file in $config_path"
cat > "$config_path" <<EOF
ui = $enable_ui
storage "gcs" {
bucket = "$gcs_bucket"
credentials_file = "$gcp_creds_file"
}
ha_storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
scheme = "http"
service = "vault"
}
# HA settings
cluster_addr = "https://$instance_ip_address:$cluster_port"
api_addr = "https://$instance_ip_address:$port"
listener "tcp" {
address = "0.0.0.0:$port"
cluster_address = "0.0.0.0:$cluster_port"
tls_cert_file = "$tls_cert_file"
tls_key_file = "$tls_key_file"
}
EOF
fi
chown "$user:$user" "$config_path"
}
function generate_supervisor_config {
local readonly supervisor_config_path="$1"
local readonly vault_config_dir="$2"
local readonly vault_bin_dir="$3"
local readonly vault_log_dir="$4"
local readonly vault_log_level="$5"
local readonly vault_user="$6"
log_info "Creating Supervisor config file to run Vault in $supervisor_config_path"
cat > "$supervisor_config_path" <<EOF
[program:vault]
command=$vault_bin_dir/vault server -config $vault_config_dir -log-level=$vault_log_level
stdout_logfile=$vault_log_dir/vault-stdout.log
stderr_logfile=$vault_log_dir/vault-error.log
numprocs=1
autostart=true
autorestart=true
stopsignal=INT
user=$vault_user
EOF
}
function start_vault {
log_info "Reloading Supervisor config and starting Vault"
supervisorctl reread
supervisorctl update
}
# Based on: http://unix.stackexchange.com/a/7732/215969
function get_owner_of_path {
local readonly path="$1"
ls -ld "$path" | awk '{print $3}'
}
function run {
local gcs_bucket=""
local tls_cert_file=""
local tls_key_file=""
local gcp_creds_file=""
local port="$DEFAULT_PORT"
local cluster_port=""
local config_dir=""
local bin_dir=""
local log_dir=""
local log_level="$DEFAULT_LOG_LEVEL"
local user=""
local skip_vault_config="false"
local enable_ui="false"
local enable_auto_unseal="false"
local auto_unseal_project=""
local auto_unseal_region=""
local auto_unseal_key_ring=""
local auto_unseal_crypto_key=""
local all_args=()
while [[ $# > 0 ]]; do
local key="$1"
case "$key" in
--tls-cert-file)
tls_cert_file="$2"
shift
;;
--tls-key-file)
tls_key_file="$2"
shift
;;
--gcs-bucket)
gcs_bucket="$2"
shift
;;
--gcp-creds-file)
gcp_creds_file="$2"
shift
;;
--port)
port="$2"
shift
;;
--cluster-port)
cluster_port="$2"
shift
;;
--config-dir)
config_dir="$2"
shift
;;
--bin-dir)
bin_dir="$2"
shift
;;
--log-dir)
log_dir="$2"
shift
;;
--log-level)
log_level="$2"
shift
;;
--user)
user="$2"
shift
;;
--skip-vault-config)
skip_vault_config="true"
;;
--enable-ui)
enable_ui="true"
;;
--enable-auto-unseal)
enable_auto_unseal="true"
;;
--auto-unseal-key-project-id)
auto_unseal_project="$2"
shift
;;
--auto-unseal-key-region)
auto_unseal_region="$2"
shift
;;
--auto-unseal-key-ring)
auto_unseal_key_ring="$2"
shift
;;
--auto-unseal-crypto-key-name)
auto_unseal_crypto_key="$2"
shift
;;
--help)
print_usage
exit
;;
*)
log_error "Unrecognized argument: $key"
print_usage
exit 1
;;
esac
shift
done
assert_not_empty "--tls-cert-file" "$tls_cert_file"
assert_not_empty "--tls-key-file" "$tls_key_file"
assert_not_empty "--gcs-bucket" "$gcs_bucket"
assert_is_installed "supervisorctl"
assert_is_installed "curl"
if [[ -z "$config_dir" ]]; then
config_dir=$(cd "$SCRIPT_DIR/../config" && pwd)
fi
if [[ -z "$bin_dir" ]]; then
bin_dir=$(cd "$SCRIPT_DIR/../bin" && pwd)
fi
if [[ -z "$log_dir" ]]; then
log_dir=$(cd "$SCRIPT_DIR/../log" && pwd)
fi
if [[ -z "$user" ]]; then
user=$(get_owner_of_path "$config_dir")
fi
if [[ -z "$cluster_port" ]]; then
cluster_port=$(( $port + 1 ))
fi
if [[ "$skip_vault_config" == "true" ]]; then
log_info "The --skip-vault-config flag is set, so will not generate a default Vault config file."
else
generate_vault_config "$tls_cert_file" "$tls_key_file" "$port" "$cluster_port" "$config_dir" "$user" "$gcs_bucket" "$gcp_creds_file" \
"$enable_auto_unseal" "$auto_unseal_project" "$auto_unseal_region" "$auto_unseal_key_ring" "$auto_unseal_crypto_key" "$enable_ui"
fi
generate_supervisor_config "$SUPERVISOR_CONFIG_PATH" "$config_dir" "$bin_dir" "$log_dir" "$log_level" "$user"
start_vault
}
run "$@"