sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/ssm/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 ssm
    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 SSM Parameter Store"
   122    set +o errexit
   123    set +o nounset
   124    set +o pipefail
   125    out=$(
   126      aws ssm ${ENDPOINT} --region ${REGION} delete-parameter --name "${id}" 2>&1
   127    )
   128    local delete_return=$?
   129    set -o errexit
   130    set -o nounset
   131    set -o pipefail
   132    check_aws_command "SSM::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 SSM Parameter Store"
   149    log::info "getting secret value from AWS SSM Parameter Store"
   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 ssm ${ENDPOINT} --region ${REGION} get-parameter --output text --query 'Parameter.Value' --with-decryption --name "${id}" 2>&1
   159    )
   160    local get_return=$?
   161    check_aws_command "SSM::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}.b64.gz"
   171    echo "${data}" >>${FILE}.b64.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  cat "${FILE}.b64.gz" | base64 -d > "${FILE}.gz"
   191  rm -f "${FILE}.b64.gz"
   192  gunzip "${FILE}.gz"
   193  GUNZIP_RETURN=$?
   194  if [ ${GUNZIP_RETURN} -ne 0 ]; then
   195    log::error_exit "could not unzip data" 4
   196  fi
   197  
   198  log::info "restarting cloud-init"
   199  systemctl restart cloud-init
   200  log::success_exit
   201  `