Browse Source
Rewrite AWS API signing code
Rewrite AWS API signing code
- Adds support for signing custom headers - Adds support for Amazon Certificate Manager calls - Place in a lib for use with DNS and deploy pluginspull/1313/head
2 changed files with 198 additions and 1 deletions
-
2acme.sh
-
197lib/aws.sh
@ -0,0 +1,197 @@ |
|||
#!/usr/bin/env sh |
|||
|
|||
# usage: _aws <svc> <svcargs...> |
|||
# |
|||
# services: |
|||
# |
|||
# ACM: _aws acm <rpc> <region> [json] |
|||
# _aws acm ListCertificates us-east-1 '{"MaxItems": 2}' |
|||
|
|||
_aws() { |
|||
_svc="$1" # _args=... |
|||
shift |
|||
if ! _aws_auth; then |
|||
return 255 |
|||
fi |
|||
n="$(printf '\nn')" n="${n%n}" |
|||
"_aws_svc_$_svc" "$@" |
|||
} |
|||
|
|||
# private |
|||
|
|||
# services |
|||
|
|||
_aws_svc_acm() { |
|||
_rpc="$1" _region="$2" _json="$3" |
|||
|
|||
_empty='{}' |
|||
_rpc="x-amz-target:CertificateManager.$_rpc" |
|||
_type='content-type:application/x-amz-json-1.1' |
|||
|
|||
_aws_wrap '"__type":' \ |
|||
POST "acm.$_region.amazonaws.com" '/' '' "$_region/acm" \ |
|||
"$_rpc$n$_type" "${_json:-$_empty}" |
|||
} |
|||
|
|||
# core |
|||
|
|||
_aws_wrap() { |
|||
_check="$1" # _args=... |
|||
shift |
|||
_resp="$(_aws_req4 "$@")" |
|||
_ret="$?" |
|||
_debug2 _resp "$_resp" |
|||
if [ "$_ret" -eq 0 ] && _contains "$_resp" "$_check"; then |
|||
_err "Response error: $_resp" |
|||
return 1 |
|||
fi |
|||
printf %s "$_resp" |
|||
return "$_ret" |
|||
} |
|||
|
|||
_aws_req4() { |
|||
_verb="$1" _host="$2" _path="$3" _query="$4" _svc="$5" _hdrs="$6" _data="$7" |
|||
|
|||
_debug _verb "$_verb" |
|||
_debug _host "$_host" |
|||
_debug _path "$_path" |
|||
_debug _query "$_query" |
|||
_debug _svc "$_svc" |
|||
_debug _hdrs "$_hdrs" |
|||
_debug _data "$_data" |
|||
|
|||
_date="$(date -u +%Y%m%dT%H%M%SZ)" |
|||
_debug2 _date "$_date" |
|||
|
|||
_hdrs="host:$_host${n}x-amz-date:$_date$n$_hdrs" |
|||
if [ "$AWS_SESSION_TOKEN" ]; then |
|||
_hdrs="$_hdrs${n}x-amz-security-token:$AWS_SESSION_TOKEN" |
|||
fi |
|||
_hdrs="$(printf %s "$_hdrs" | sort | sed '/^$/d')$n" |
|||
_debug2 _hdrs "$_hdrs" |
|||
|
|||
_keys="$( |
|||
printf %s "$_hdrs" | while read -r _hdr; do |
|||
printf '%s\n' "${_hdr%%:*}" |
|||
done | paste -sd ';' |
|||
)" |
|||
_debug2 _keys "$_keys" |
|||
|
|||
_scope="$(printf %s "$_date" | cut -c 1-8)/$_svc/aws4_request" |
|||
_debug2 _scope "$_scope" |
|||
|
|||
_hash='sha256' |
|||
_debug3 _hash "$_hash" |
|||
_algo='AWS4-HMAC-SHA256' |
|||
_debug3 _algo "$_algo" |
|||
|
|||
_bdy="$(printf %s "$_data" | _digest "$_hash" hex)" |
|||
_debug2 _bdy "$_bdy" |
|||
_req="$_verb$n$_path$n$_query$n$_hdrs$n$_keys$n$_bdy" |
|||
_debug2 _req "$_req" |
|||
_req="$(printf %s "$_req" | _digest "$_hash" hex)" |
|||
_debug2 _req "$_req" |
|||
_str="$_algo$n$_date$n$_scope$n$_req" |
|||
_debug2 _str "$_str" |
|||
|
|||
_sig="$(printf %s "AWS4$AWS_SECRET_ACCESS_KEY" | _hex_dump | tr -d ' ')" |
|||
_secure_debug2 _sig "$_sig" |
|||
for _step in $(printf %s "$_scope" | tr '/' ' ') "$_str"; do |
|||
_debug2 _step "$_step" |
|||
_sig="$(printf %s "$_step" | _hmac "$_hash" "$_sig" hex)" |
|||
_debug2 _sig "$_sig" |
|||
done |
|||
|
|||
_cred="$AWS_ACCESS_KEY_ID/$_scope" |
|||
_auth="$_algo Credential=$_cred, SignedHeaders=$_keys, Signature=$_sig" |
|||
_debug2 _auth "$_auth" |
|||
|
|||
_url="https://$_host$_path" |
|||
if [ "$_query" ]; then |
|||
_url="$_url?$_query" |
|||
fi |
|||
|
|||
unset i |
|||
while read -r _line; do |
|||
i=$((i + 1)) |
|||
eval "_H$i=\"\$_line\"; _debug2 _H$i \"\$_H$i\"" |
|||
done <<-END |
|||
authorization:$_auth |
|||
$_hdrs |
|||
END |
|||
|
|||
case "$(printf %s "$_verb" | tr '[:upper:]' '[:lower:]')" in |
|||
get) _get "$_url" ;; |
|||
post) _post "$_data" "$_url" ;; |
|||
*) _err '_aws only supports get and post' ;; |
|||
esac |
|||
} |
|||
|
|||
# credentials |
|||
|
|||
_aws_auth() { |
|||
_aws_auth_environment || _aws_auth_container_role || _aws_auth_instance_role |
|||
} |
|||
|
|||
_aws_auth_environment() { |
|||
AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-$(_readaccountconf_mutable AWS_ACCESS_KEY_ID)}" |
|||
AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-$(_readaccountconf_mutable AWS_SECRET_ACCESS_KEY)}" |
|||
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then |
|||
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY |
|||
return 1 |
|||
fi |
|||
if [ -z "$_aws_using_role" ]; then |
|||
_saveaccountconf_mutable AWS_ACCESS_KEY_ID "$AWS_ACCESS_KEY_ID" |
|||
_saveaccountconf_mutable AWS_SECRET_ACCESS_KEY "$AWS_SECRET_ACCESS_KEY" |
|||
fi |
|||
} |
|||
|
|||
_aws_auth_container_role() { |
|||
# automatically set if running inside ECS |
|||
if [ -z "$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" ]; then |
|||
_debug 'no ECS environment variable detected' |
|||
return 1 |
|||
fi |
|||
_aws_auth_metadata "169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI" |
|||
} |
|||
|
|||
_aws_auth_instance_role() { |
|||
_url='http://169.254.169.254/latest/meta-data/iam/security-credentials/' |
|||
_debug _url "$_url" |
|||
_aws_role=$(_get "$_url" '' 1) |
|||
if [ "$?" -gt 0 ]; then |
|||
_debug 'unable to fetch IAM role from instance metadata' |
|||
return 1 |
|||
fi |
|||
_debug _aws_role "$_aws_role" |
|||
_aws_auth_metadata "$_url$_aws_role" |
|||
} |
|||
|
|||
_aws_auth_metadata() { |
|||
_url="$1" |
|||
|
|||
_aws_creds="$( |
|||
_get "$_url" "" 1 \ |
|||
| _normalizeJson \ |
|||
| tr '{,}' '\n' \ |
|||
| while read -r _line; do |
|||
_key="$(printf %s "${_line%%:*}" | tr -d '"')" _value="${_line#*:}" |
|||
_debug3 _key "$_key" |
|||
_secure_debug3 _value "$_value" |
|||
case "$_key" in |
|||
AccessKeyId) printf '%s\n' "AWS_ACCESS_KEY_ID=$_value" ;; |
|||
SecretAccessKey) printf '%s\n' "AWS_SECRET_ACCESS_KEY=$_value" ;; |
|||
Token) printf '%s\n' "AWS_SESSION_TOKEN=$_value" ;; |
|||
esac |
|||
done \ |
|||
| paste -sd' ' - |
|||
)" |
|||
_secure_debug _aws_creds "$_aws_creds" |
|||
|
|||
if [ -z "$_aws_creds" ]; then |
|||
return 1 |
|||
fi |
|||
|
|||
eval "$_aws_creds" |
|||
_aws_using_role=true |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue