sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/secretsmanager/secret_fetch_script.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package secretsmanager 18 19 // nolint: gosec 20 const secretFetchScript = `#cloud-boothook 21 #!/bin/bash 22 23 # Copyright 2020 The Kubernetes Authors. 24 # 25 # Licensed under the Apache License, Version 2.0 (the "License"); 26 # you may not use this file except in compliance with the License. 27 # You may obtain a copy of the License at 28 # 29 # http://www.apache.org/licenses/LICENSE-2.0 30 # 31 # Unless required by applicable law or agreed to in writing, software 32 # distributed under the License is distributed on an "AS IS" BASIS, 33 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 34 # See the License for the specific language governing permissions and 35 # limitations under the License. 36 37 set -o errexit 38 set -o nounset 39 set -o pipefail 40 41 umask 006 42 43 REGION="{{.Region}}" 44 if [ "{{.Endpoint}}" != "" ]; then 45 ENDPOINT="--endpoint-url {{.Endpoint}}" 46 fi 47 SECRET_PREFIX="{{.SecretPrefix}}" 48 CHUNKS="{{.Chunks}}" 49 FILE="/etc/secret-userdata.txt" 50 FINAL_INDEX=$((CHUNKS - 1)) 51 52 # Log an error and exit. 53 # Args: 54 # $1 Message to log with the error 55 # $2 The error code to return 56 log::error_exit() { 57 local message="${1}" 58 local code="${2}" 59 60 log::error "${message}" 61 log::error "aws.cluster.x-k8s.io encrypted cloud-init script $0 exiting with status ${code}" 62 exit "${code}" 63 } 64 65 log::success_exit() { 66 log::info "aws.cluster.x-k8s.io encrypted cloud-init script $0 finished" 67 exit 0 68 } 69 70 # Log an error but keep going. 71 log::error() { 72 local message="${1}" 73 timestamp=$(date --iso-8601=seconds) 74 echo "!!! [${timestamp}] ${1}" >&2 75 shift 76 for message; do 77 echo " ${message}" >&2 78 done 79 } 80 81 # Print a status line. Formatted to show up in a stream of output. 82 log::info() { 83 timestamp=$(date --iso-8601=seconds) 84 echo "+++ [${timestamp}] ${1}" 85 shift 86 for message; do 87 echo " ${message}" 88 done 89 } 90 91 check_aws_command() { 92 local command="${1}" 93 local code="${2}" 94 local out="${3}" 95 local sanitised="${out//[$'\t\r\n']/}" 96 case ${code} in 97 "0") 98 log::info "AWS CLI reported successful execution for ${command}" 99 ;; 100 "2") 101 log::error "AWS CLI reported that it could not parse ${command}" 102 log::error "${sanitised}" 103 ;; 104 "130") 105 log::error "AWS CLI reported SIGINT signal during ${command}" 106 log::error "${sanitised}" 107 ;; 108 "255") 109 log::error "AWS CLI reported service error for ${command}" 110 log::error "${sanitised}" 111 ;; 112 *) 113 log::error "AWS CLI reported unknown error ${code} for ${command}" 114 log::error "${sanitised}" 115 ;; 116 esac 117 } 118 delete_secret_value() { 119 local id="${SECRET_PREFIX}-${1}" 120 local out 121 log::info "deleting secret from AWS Secrets Manager" 122 set +o errexit 123 set +o nounset 124 set +o pipefail 125 out=$( 126 aws secretsmanager ${ENDPOINT} --region ${REGION} delete-secret --force-delete-without-recovery --secret-id "${id}" 2>&1 127 ) 128 local delete_return=$? 129 set -o errexit 130 set -o nounset 131 set -o pipefail 132 check_aws_command "SecretsManager::DeleteSecret" "${delete_return}" "${out}" 133 if [ ${delete_return} -ne 0 ]; then 134 log::error_exit "Could not delete secret value" 2 135 fi 136 } 137 138 delete_secrets() { 139 for i in $(seq 0 ${FINAL_INDEX}); do 140 delete_secret_value "$i" 141 done 142 } 143 144 get_secret_value() { 145 local chunk=$1 146 local id="${SECRET_PREFIX}-${chunk}" 147 148 log::info "getting userdata from AWS Secrets Manager" 149 log::info "getting secret value from AWS Secrets Manager" 150 151 local data 152 set +o errexit 153 set +o nounset 154 set +o pipefail 155 data=$( 156 set +e 157 set +o pipefail 158 aws secretsmanager ${ENDPOINT} --region ${REGION} get-secret-value --output text --query 'SecretBinary' --secret-id "${id}" 2>&1 159 ) 160 local get_return=$? 161 check_aws_command "SecretsManager::GetSecretValue" "${get_return}" "${data}" 162 set -o errexit 163 set -o nounset 164 set -o pipefail 165 if [ ${get_return} -ne 0 ]; then 166 log::error "could not get secret value, deleting secret" 167 delete_secrets 168 log::error_exit "could not get secret value, but secret was deleted" 1 169 fi 170 log::info "appending data to temporary file ${FILE}.gz" 171 echo "${data}" | base64 -d >>${FILE}.gz 172 } 173 174 log::info "aws.cluster.x-k8s.io encrypted cloud-init script $0 started" 175 log::info "secret prefix: ${SECRET_PREFIX}" 176 log::info "secret count: ${CHUNKS}" 177 178 if test -f "${FILE}"; then 179 log::info "encrypted userdata already written to disk" 180 log::success_exit 181 fi 182 183 for i in $(seq 0 "${FINAL_INDEX}"); do 184 get_secret_value "$i" 185 done 186 187 delete_secrets 188 189 log::info "decompressing userdata to ${FILE}" 190 gunzip "${FILE}.gz" 191 GUNZIP_RETURN=$? 192 if [ ${GUNZIP_RETURN} -ne 0 ]; then 193 log::error_exit "could not unzip data" 4 194 fi 195 196 log::info "restarting cloud-init" 197 systemctl restart cloud-init 198 log::success_exit 199 `