지난번에 게시한 AWS Signature v4를 이용한 S3 객체 다운로드/업로드의 ShellScript도 함께 작성하게 되었다.
(AWS Signature 소개 및 PowerShell 버전 참조)
ShellScript 버전은 PowerShell보다 참조할 자료가 많아 AWS4-HMAC-SHA256 알고리즘 구현이 쉬웠고, 필요했던 기능인 s3에 대해서만 객체 다운로드/업로드 기능을 구현했다.
#!bin/bash
## Set my credential ##
ACCESS_KEY=###############
SECRET_KEY=#########################
REGION=ap-northeast-2
urlEncode() {
LINE="$1"
LENGTH="${#LINE}"
I=0
while [ $I -lt $LENGTH ]
do
C="${LINE:I:1}"
case $C in
[a-zA-Z0-9.~_-]) printf "$C" ;;
*) printf '%%%02X' "'$C" ;;
esac
let I=I+1
done
}
getHexaDecimalString() {
read LINE
LENGTH="${#LINE}"
I=0
while [ $I -lt $LENGTH ]
do
C="${LINE:I:1}"
printf '%2x' "'$C"
let I=I+1
done
}
getSignatureKey() {
SECRET_KEY=$1
DATESTAMP=$2
REGIONNAME=$3
SERVICENAME=$4
STRING_TO_SIGN=$5
HEX_KEY=$(echo -n "AWS4${SECRET_KEY}" | getHexaDecimalString)
HEX_KEY=$(echo -n "${DATESTAMP}" | openssl dgst -sha256 -mac HMAC -macopt hexkey:${HEX_KEY})
HEX_KEY=$(echo -n "${REGIONNAME}" | openssl dgst -sha256 -mac HMAC -macopt hexkey:${HEX_KEY#* })
HEX_KEY=$(echo -n "${SERVICENAME}" | openssl dgst -sha256 -mac HMAC -macopt hexkey:${HEX_KEY#* })
SIGNING_KEY=$(echo -n "aws4_request" | openssl dgst -sha256 -mac HMAC -macopt hexkey:${HEX_KEY#* })
SIGNATURE=$(echo -en "${STRING_TO_SIGN}" | openssl dgst -binary -hex -sha256 -mac HMAC -macopt hexkey:${SIGNING_KEY#* })
echo "${SIGNATURE#* }"
}
getHexaHash() {
PAYLOAD="$@"
HASH=$(echo -n "${PAYLOAD}" | openssl dgst -sha256)
echo "${HASH#* }"
}
### Main ###
if [ -z $REGION ] || [ -z $ACCESS_KEY ] || [ -z $SECRET_KEY ]
then
echo "Please set ACCESS_KEY, SECRET_KEY and REGION variables"
exit 1
fi
AK="$ACCESS_KEY"
SK="$SECRET_KEY"
REGION="$REGION"
[ $# -ne 8 ] && exit 2
while getopts ":m:b:k:e:" OPT; do
case $OPT in
m)
HTTPMETHOD=$OPTARG # GET or PUT
;;
b)
BUCKET=$OPTARG
;;
k)
S3KEY=$OPTARG
;;
e)
EXPIRES=$OPTARG
;;
*)
echo "Invalid option: -$OPTARG" >&2
exit 3
;;
esac
done
SERVICENAME="s3"
HOST="${BUCKET}.${SERVICENAME}.${REGION}.amazonaws.com"
ENDPOINT="https://${BUCKET}.${SERVICENAME}.${REGION}.amazonaws.com"
# step 1. Create a Canonical request
AMZ_DATE=$(date -u +%Y%m%dT%H%M%SZ)
DATESTAMP=$(date -u +%Y%m%d)
AMZ_EXPIRES=$((${EXPIRES}*60)) # min
CANONICAL_URI="/${S3KEY}"
CANONICAL_HEADERS="host:${HOST}\n"
SIGNED_HEADERS="host"
PAYLOAD_HASH="UNSIGNED-PAYLOAD"
ALGORITHM="AWS4-HMAC-SHA256"
CREDENTIAL_SCOPE="${DATESTAMP}/${REGION}/${SERVICENAME}/aws4_request"
CANONICAL_QUERYSTRING="X-Amz-Algorithm=${ALGORITHM}"
CANONICAL_QUERYSTRING="${CANONICAL_QUERYSTRING}&X-Amz-Credential=$(urlEncode "${AK}/${CREDENTIAL_SCOPE}")"
CANONICAL_QUERYSTRING="${CANONICAL_QUERYSTRING}&X-Amz-Date=${AMZ_DATE}"
CANONICAL_QUERYSTRING="${CANONICAL_QUERYSTRING}&X-Amz-Expires=${AMZ_EXPIRES}"
CANONICAL_QUERYSTRING="${CANONICAL_QUERYSTRING}&X-Amz-SignedHeaders=${SIGNED_HEADERS}"
CANONICAL_REQUEST="${HTTPMETHOD}\n${CANONICAL_URI}\n${CANONICAL_QUERYSTRING}\n${CANONICAL_HEADERS}\n${SIGNED_HEADERS}\n${PAYLOAD_HASH}"
# step 2. String To Sign
STRING_TO_SIGN="${ALGORITHM}\n${AMZ_DATE}\n${CREDENTIAL_SCOPE}\n$(getHexaHash "$(echo -e "${CANONICAL_REQUEST}")")"
# step 3. Signature
SIGNATURE="$(getSignatureKey $SK $DATESTAMP $REGION $SERVICENAME $STRING_TO_SIGN)"
# step 4. Create a request URL
CANONICAL_QUERYSTRING="${CANONICAL_QUERYSTRING}&X-Amz-Signature=${SIGNATURE}"
REQUEST_URL=${ENDPOINT}/${S3KEY}?${CANONICAL_QUERYSTRING}
CLI="curl $(if [[ "$HTTPMETHOD" == "GET" ]]; then echo "-o"; else echo "-T"; fi) \"${S3KEY##*/}\" \"$REQUEST_URL\""
echo "$CLI"
사용방법은 ACCESS_KEY, SECRET_KEY, REGION 값을 자신의 설정에 알맞게 입력하고 쉘 스크립트 실행 시 argument 값을 각각 지정하면 해당 파라미터에 대해 curl + Request URL을 출력한다.
실행 시 입력해야 하는 argument 목록은 다음과 같다.
| Argument | Value |
| m (method) | GET 또는 PUT (다운로드/업로드) |
| b (bucket) | Bucket Name |
| k (key) | Key Name |
| e (expires) | 120 (분) |
(ex. bash s3web.sh -m GET -b s3-mybucket -k mydir/myobj -e 120)
PowerShell 버전과는 달리 실행 시 인자 값을 입력받도록 했는데, 필요에 따라 입력받는 부분을 고정 값으로 변경하여 사용하면 된다.
만약 Request URL 실행문을 출력하는 대신 스크립트 자체에서 실행되도록 하고 싶다면 마지막 줄에 eval "${CLI}" 를 추가하도록 한다.