18 changed files with 1546 additions and 283 deletions
@ -1,5 +1,5 @@
|
||||
|
||||
[defaults] |
||||
host_key_checking = True |
||||
callback_plugins = ./callback_plugins |
||||
|
||||
stdout_callback = default-with-json-interleaved |
@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env bash |
||||
# |
||||
# Delete a file from S3 |
||||
# (c) 2015 Chi Vinh Le <cvl@winged.kiwi> |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not |
||||
# use this file except in compliance with the License. You may obtain a copy of |
||||
# the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
||||
# License for the specific language governing permissions and limitations under |
||||
# the License. |
||||
|
||||
set -euo pipefail |
||||
|
||||
readonly PROJECT_PATH=$( cd $(dirname $0) ; cd ../; pwd -P ) |
||||
readonly SCRIPT_NAME="$(basename $0)" |
||||
readonly METHOD="DELETE" |
||||
|
||||
# Includes |
||||
source ${PROJECT_PATH}/lib/s3-common.sh |
||||
|
||||
## |
||||
# Print help and exit |
||||
# Arguments: |
||||
# $1 int exit code |
||||
# Output: |
||||
# string help |
||||
## |
||||
printUsageAndExitWith() { |
||||
printf "Usage:\n" |
||||
printf " ${SCRIPT_NAME} [-vi] [-k key] [-s file] [-r region] resource_path\n" |
||||
printf " ${SCRIPT_NAME} -h\n" |
||||
printf "Example:\n" |
||||
printf " ${SCRIPT_NAME} -k key -s secret -r eu-central-1 /bucket/file.ext\n" |
||||
printf "Options:\n" |
||||
printf " --debug\tEnable debugging mode\n" |
||||
printf " -h,--help\tPrint this help\n" |
||||
printf " -i,--insecure\tUse http instead of https\n" |
||||
printf " -k,--key\tAWS Access Key ID. Default to environment variable AWS_ACCESS_KEY_ID\n" |
||||
printf " -r,--region\tAWS S3 Region. Default to environment variable AWS_DEFAULT_REGION\n" |
||||
printf " -s,--secret\tFile containing AWS Secret Access Key. If not set, secret will be environment variable AWS_SECRET_ACCESS_KEY\n" |
||||
printf " -t,--token\tSecurity token for temporary credentials. If not set, token will be environment variable AWS_SECURITY_TOKEN\n" |
||||
printf " -v,--verbose\tVerbose output\n" |
||||
printf " --version\tShow version\n" |
||||
exit $1 |
||||
} |
||||
|
||||
## |
||||
# Parse command line and set global variables |
||||
# Arguments: |
||||
# $@ command line |
||||
# Globals: |
||||
# AWS_ACCESS_KEY_ID string |
||||
# AWS_SECRET_ACCESS_KEY string |
||||
# AWS_REGION string |
||||
# AWS_SECURITY_TOKEN string |
||||
# RESOURCE_PATH string |
||||
# VERBOSE bool |
||||
# INSECURE bool |
||||
# DEBUG bool |
||||
## |
||||
parseCommandLine() { |
||||
# Init globals |
||||
AWS_REGION=${AWS_DEFAULT_REGION:-""} |
||||
AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-""} |
||||
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-""} |
||||
AWS_SECURITY_TOKEN=${AWS_SECURITY_TOKEN:-""} |
||||
VERBOSE=false |
||||
INSECURE=false |
||||
DEBUG=false |
||||
|
||||
# Parse options |
||||
local remaining= |
||||
local secretKeyFile= |
||||
while [[ $# > 0 ]]; do |
||||
local key="$1" |
||||
case ${key} in |
||||
--version) showVersionAndExit;; |
||||
--debug) DEBUG=true;; |
||||
-h|--help) printUsageAndExitWith 0;; |
||||
-v|--verbose) VERBOSE=true;; |
||||
-i|--insecure) INSECURE=true;; |
||||
-r|--region) assertArgument $@; AWS_REGION=$2; shift;; |
||||
-k|--key) assertArgument $@; AWS_ACCESS_KEY_ID=$2; shift;; |
||||
-s|--secret) assertArgument $@; secretKeyFile=$2; shift;; |
||||
-t|--token) assertArgument $@; AWS_SECURITY_TOKEN=$2; shift;; |
||||
-*) err "Unknown option $1" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE};; |
||||
*) remaining="${remaining} \"${key}\"";; |
||||
esac |
||||
shift |
||||
done |
||||
|
||||
# Set the non-parameters back into the positional parameters ($1 $2 ..) |
||||
eval set -- ${remaining} |
||||
|
||||
# Read secret file if set |
||||
if ! [[ -z "${secretKeyFile}" ]]; then |
||||
AWS_SECRET_ACCESS_KEY=$(processAWSSecretFile "${secretKeyFile}") |
||||
fi |
||||
|
||||
# Parse arguments |
||||
if [[ $# != 1 ]]; then |
||||
err "You need to specify the resource path to download e.g. /bucket/file.ext" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
|
||||
assertResourcePath "$1" |
||||
RESOURCE_PATH="$1" |
||||
|
||||
if [[ -z "${AWS_REGION}" ]]; then |
||||
err "AWS Region not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
if [[ -z "${AWS_ACCESS_KEY_ID}" ]]; then |
||||
err "AWS Access Key ID not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
if [[ -z "${AWS_SECRET_ACCESS_KEY}" ]]; then |
||||
err "AWS Secret Access Key not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
|
||||
# Freeze globals |
||||
readonly AWS_REGION |
||||
readonly AWS_ACCESS_KEY_ID |
||||
readonly AWS_SECRET_ACCESS_KEY |
||||
readonly RESOURCE_PATH |
||||
readonly DEBUG |
||||
readonly VERBOSE |
||||
readonly INSECURE |
||||
} |
||||
|
||||
## |
||||
# Main routine |
||||
## |
||||
main() { |
||||
checkEnvironment |
||||
parseCommandLine $@ |
||||
performRequest |
||||
} |
||||
|
||||
main $@ |
@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env bash |
||||
# |
||||
# Download a file from S3 |
||||
# (c) 2015 Chi Vinh Le <cvl@winged.kiwi> |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not |
||||
# use this file except in compliance with the License. You may obtain a copy of |
||||
# the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
||||
# License for the specific language governing permissions and limitations under |
||||
# the License. |
||||
|
||||
set -euo pipefail |
||||
|
||||
readonly PROJECT_PATH=$( cd $(dirname $0) ; cd ../; pwd -P ) |
||||
readonly SCRIPT_NAME="$(basename $0)" |
||||
readonly METHOD="GET" |
||||
|
||||
# Includes |
||||
source ${PROJECT_PATH}/lib/s3-common.sh |
||||
|
||||
## |
||||
# Print help and exit |
||||
# Arguments: |
||||
# $1 int exit code |
||||
# Output: |
||||
# string help |
||||
## |
||||
printUsageAndExitWith() { |
||||
printf "Usage:\n" |
||||
printf " ${SCRIPT_NAME} [-vi] [-k key] [-s file] [-r region] resource_path\n" |
||||
printf " ${SCRIPT_NAME} -h\n" |
||||
printf "Example:\n" |
||||
printf " ${SCRIPT_NAME} -k key -s secret -r eu-central-1 /bucket/file.ext\n" |
||||
printf "Options:\n" |
||||
printf " --debug\tEnable debugging mode\n" |
||||
printf " -h,--help\tPrint this help\n" |
||||
printf " -i,--insecure\tUse http instead of https\n" |
||||
printf " -k,--key\tAWS Access Key ID. Default to environment variable AWS_ACCESS_KEY_ID\n" |
||||
printf " -r,--region\tAWS S3 Region. Default to environment variable AWS_DEFAULT_REGION\n" |
||||
printf " -s,--secret\tFile containing AWS Secret Access Key. If not set, secret will be environment variable AWS_SECRET_ACCESS_KEY\n" |
||||
printf " -t,--token\tSecurity token for temporary credentials. If not set, token will be environment variable AWS_SECURITY_TOKEN\n" |
||||
printf " -v,--verbose\tVerbose output\n" |
||||
printf " --version\tShow version\n" |
||||
exit $1 |
||||
} |
||||
|
||||
## |
||||
# Parse command line and set global variables |
||||
# Arguments: |
||||
# $@ command line |
||||
# Globals: |
||||
# AWS_ACCESS_KEY_ID string |
||||
# AWS_SECRET_ACCESS_KEY string |
||||
# AWS_REGION string |
||||
# AWS_SECURITY_TOKEN string |
||||
# RESOURCE_PATH string |
||||
# VERBOSE bool |
||||
# INSECURE bool |
||||
# DEBUG bool |
||||
## |
||||
parseCommandLine() { |
||||
# Init globals |
||||
AWS_REGION=${AWS_DEFAULT_REGION:-""} |
||||
AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-""} |
||||
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-""} |
||||
AWS_SECURITY_TOKEN=${AWS_SECURITY_TOKEN:-""} |
||||
VERBOSE=false |
||||
INSECURE=false |
||||
DEBUG=false |
||||
|
||||
# Parse options |
||||
local remaining= |
||||
local secretKeyFile= |
||||
while [[ $# > 0 ]]; do |
||||
local key="$1" |
||||
case ${key} in |
||||
--version) showVersionAndExit;; |
||||
--debug) DEBUG=true;; |
||||
-h|--help) printUsageAndExitWith 0;; |
||||
-v|--verbose) VERBOSE=true;; |
||||
-i|--insecure) INSECURE=true;; |
||||
-r|--region) assertArgument $@; AWS_REGION=$2; shift;; |
||||
-k|--key) assertArgument $@; AWS_ACCESS_KEY_ID=$2; shift;; |
||||
-s|--secret) assertArgument $@; secretKeyFile=$2; shift;; |
||||
-t|--token) assertArgument $@; AWS_SECURITY_TOKEN=$2; shift;; |
||||
-*) err "Unknown option $1" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE};; |
||||
*) remaining="${remaining} \"${key}\"";; |
||||
esac |
||||
shift |
||||
done |
||||
|
||||
# Set the non-parameters back into the positional parameters ($1 $2 ..) |
||||
eval set -- ${remaining} |
||||
|
||||
# Read secret file if set |
||||
if ! [[ -z "${secretKeyFile}" ]]; then |
||||
AWS_SECRET_ACCESS_KEY=$(processAWSSecretFile "${secretKeyFile}") |
||||
fi |
||||
|
||||
# Parse arguments |
||||
if [[ $# != 1 ]]; then |
||||
err "You need to specify the resource path to download e.g. /bucket/file.ext" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
|
||||
assertResourcePath "$1" |
||||
RESOURCE_PATH="$1" |
||||
|
||||
if [[ -z "${AWS_REGION}" ]]; then |
||||
err "AWS Region not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
if [[ -z "${AWS_ACCESS_KEY_ID}" ]]; then |
||||
err "AWS Access Key ID not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
if [[ -z "${AWS_SECRET_ACCESS_KEY}" ]]; then |
||||
err "AWS Secret Access Key not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
|
||||
# Freeze globals |
||||
readonly AWS_REGION |
||||
readonly AWS_ACCESS_KEY_ID |
||||
readonly AWS_SECRET_ACCESS_KEY |
||||
readonly RESOURCE_PATH |
||||
readonly DEBUG |
||||
readonly VERBOSE |
||||
readonly INSECURE |
||||
} |
||||
|
||||
## |
||||
# Main routine |
||||
## |
||||
main() { |
||||
checkEnvironment |
||||
parseCommandLine $@ |
||||
performRequest |
||||
} |
||||
|
||||
main $@ |
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env bash |
||||
# |
||||
# Upload a file to S3 |
||||
# (c) 2015 Chi Vinh Le <cvl@winged.kiwi> |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not |
||||
# use this file except in compliance with the License. You may obtain a copy of |
||||
# the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
||||
# License for the specific language governing permissions and limitations under |
||||
# the License. |
||||
|
||||
set -euo pipefail |
||||
|
||||
readonly PROJECT_PATH=$( cd $(dirname $0) ; cd ../; pwd -P ) |
||||
readonly SCRIPT_NAME="$(basename $0)" |
||||
readonly METHOD="PUT" |
||||
|
||||
# Includes |
||||
source ${PROJECT_PATH}/lib/s3-common.sh |
||||
|
||||
## |
||||
# Print help and exit |
||||
# Arguments: |
||||
# $1 int exit code |
||||
# Output: |
||||
# string help |
||||
## |
||||
printUsageAndExitWith() { |
||||
printf "Usage:\n" |
||||
printf " ${SCRIPT_NAME} [--debug] [-vip] [-k key] [-r region] [-s file] [-c content_type] -T file_to_upload resource_path\n" |
||||
printf " ${SCRIPT_NAME} -h\n" |
||||
printf "Example:\n" |
||||
printf " ${SCRIPT_NAME} -k key -s secret -r eu-central-1 -T file.ext -c text/plain /bucket/file.ext\n" |
||||
printf "Options:\n" |
||||
printf " -c,--content-type\tMIME content type\n" |
||||
printf " --debug\tEnable debugging mode\n" |
||||
printf " -h,--help\tPrint this help\n" |
||||
printf " -i,--insecure\tUse http instead of https\n" |
||||
printf " -k,--key\tAWS Access Key ID. Default to environment variable AWS_ACCESS_KEY_ID\n" |
||||
printf " -p,--public\tGrant public read on uploaded file\n" |
||||
printf " -r,--region\tAWS S3 Region. Default to environment variable AWS_DEFAULT_REGION\n" |
||||
printf " -s,--secret\tFile containing AWS Secret Access Key. If not set, secret will be environment variable AWS_SECRET_ACCESS_KEY\n" |
||||
printf " -t,--token\tSecurity token for temporary credentials. If not set, token will be environment variable AWS_SECURITY_TOKEN\n" |
||||
printf " -T,--upload-file\tPath to file to upload\n" |
||||
printf " -v,--verbose\tVerbose output\n" |
||||
printf " --version\tShow version\n" |
||||
|
||||
exit $1 |
||||
} |
||||
|
||||
## |
||||
# Parse command line and set global variables |
||||
# Arguments: |
||||
# $@ command line |
||||
# Sets the following Globals: |
||||
# AWS_ACCESS_KEY_ID string |
||||
# AWS_SECRET_ACCESS_KEY string |
||||
# AWS_REGION string |
||||
# AWS_SECURITY_TOKEN string |
||||
# RESOURCE_PATH string |
||||
# FILE_TO_UPLOAD string |
||||
# CONTENT_TYPE string |
||||
# PUBLISH bool |
||||
# VERBOSE bool |
||||
# INSECURE bool |
||||
# DEBUG bool |
||||
# PUBLISH bool |
||||
## |
||||
parseCommandLine() { |
||||
# Init globals |
||||
AWS_REGION=${AWS_DEFAULT_REGION:-""} |
||||
AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-""} |
||||
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY:-""} |
||||
AWS_SECURITY_TOKEN=${AWS_SECURITY_TOKEN:-""} |
||||
FILE_TO_UPLOAD= |
||||
CONTENT_TYPE= |
||||
PUBLISH=false |
||||
VERBOSE=false |
||||
INSECURE=false |
||||
DEBUG=false |
||||
|
||||
# Parse options |
||||
local remaining= |
||||
local secretKeyFile= |
||||
while [[ $# > 0 ]]; do |
||||
local key="$1" |
||||
case ${key} in |
||||
--version) showVersionAndExit;; |
||||
--debug) DEBUG=true;; |
||||
-h|--help) printUsageAndExitWith 0;; |
||||
-v|--verbose) VERBOSE=true;; |
||||
-i|--insecure) INSECURE=true;; |
||||
-p|--publish) PUBLISH=true;; |
||||
-c|--content-type) assertArgument $@; CONTENT_TYPE=$2; shift;; |
||||
-T|--upload-file) assertArgument $@; FILE_TO_UPLOAD=$2; shift;; |
||||
-r|--region) assertArgument $@; AWS_REGION=$2; shift;; |
||||
-k|--key) assertArgument $@; AWS_ACCESS_KEY_ID=$2; shift;; |
||||
-s|--secret) assertArgument $@; secretKeyFile=$2; shift;; |
||||
-t|--token) assertArgument $@; AWS_SECURITY_TOKEN=$2; shift;; |
||||
-*) err "Unknown option $1" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE};; |
||||
*) remaining="${remaining} \"${key}\"";; |
||||
esac |
||||
shift |
||||
done |
||||
|
||||
# Set the non-parameters back into the positional parameters ($1 $2 ..) |
||||
eval set -- ${remaining} |
||||
|
||||
# Read secret file if set |
||||
if ! [[ -z "${secretKeyFile}" ]]; then |
||||
AWS_SECRET_ACCESS_KEY=$(processAWSSecretFile "${secretKeyFile}") |
||||
fi |
||||
|
||||
# Parse arguments |
||||
if [[ $# != 1 ]]; then |
||||
err "You need to specify the resource path to upload to e.g. /bucket/file.ext" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
|
||||
assertResourcePath $1 |
||||
RESOURCE_PATH="$1" |
||||
|
||||
if [[ -z "${FILE_TO_UPLOAD}" ]]; then |
||||
err "You need to specify the file to upload using -T" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
assertFileExists "${FILE_TO_UPLOAD}" |
||||
|
||||
if [[ -z "${AWS_REGION}" ]]; then |
||||
err "AWS Region not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
if [[ -z "${AWS_ACCESS_KEY_ID}" ]]; then |
||||
err "AWS Access Key ID not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
if [[ -z "${AWS_SECRET_ACCESS_KEY}" ]]; then |
||||
err "AWS Secret Access Key not specified" |
||||
printUsageAndExitWith ${INVALID_USAGE_EXIT_CODE} |
||||
fi |
||||
|
||||
# Freeze globals |
||||
readonly AWS_REGION |
||||
readonly AWS_ACCESS_KEY_ID |
||||
readonly AWS_SECRET_ACCESS_KEY |
||||
readonly RESOURCE_PATH |
||||
readonly CONTENT_TYPE |
||||
readonly PUBLISH |
||||
readonly DEBUG |
||||
readonly VERBOSE |
||||
readonly INSECURE |
||||
} |
||||
|
||||
## |
||||
# Main routine |
||||
## |
||||
main() { |
||||
checkEnvironment |
||||
parseCommandLine $@ |
||||
performRequest |
||||
} |
||||
|
||||
main $@ |
@ -0,0 +1,309 @@
|
||||
#!/usr/bin/env bash |
||||
# |
||||
# Common functions for s3-bash4 commands |
||||
# (c) 2015 Chi Vinh Le <cvl@winged.kiwi> |
||||
|
||||
# Constants |
||||
readonly VERSION="0.0.1" |
||||
|
||||
# Exit codes |
||||
readonly INVALID_USAGE_EXIT_CODE=1 |
||||
readonly INVALID_USER_DATA_EXIT_CODE=2 |
||||
readonly INVALID_ENVIRONMENT_EXIT_CODE=3 |
||||
|
||||
## |
||||
# Write error to stderr |
||||
# Arguments: |
||||
# $1 string to output |
||||
## |
||||
err() { |
||||
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')] Error: $@" >&2 |
||||
} |
||||
|
||||
|
||||
## |
||||
# Display version and exit |
||||
## |
||||
showVersionAndExit() { |
||||
printf "$VERSION\n" |
||||
exit |
||||
} |
||||
|
||||
## |
||||
# Helper for parsing the command line. |
||||
## |
||||
assertArgument() { |
||||
if [[ $# -lt 2 ]]; then |
||||
err "Option $1 needs an argument." |
||||
exit $INVALID_USAGE_EXIT_CODE |
||||
fi |
||||
} |
||||
|
||||
## |
||||
# Asserts given resource path |
||||
# Arguments: |
||||
# $1 string resource path |
||||
## |
||||
assertResourcePath() { |
||||
if [[ $1 = !(/*) ]]; then |
||||
err "Resource should start with / e.g. /bucket/file.ext" |
||||
exit $INVALID_USAGE_EXIT_CODE |
||||
fi |
||||
} |
||||
|
||||
## |
||||
# Asserts given file exists. |
||||
# Arguments: |
||||
# $1 string file path |
||||
## |
||||
assertFileExists() { |
||||
if [[ ! -f $1 ]]; then |
||||
err "$1 file doesn't exists" |
||||
exit $INVALID_USER_DATA_EXIT_CODE |
||||
fi |
||||
} |
||||
|
||||
## |
||||
# Check for valid environment. Exit if invalid. |
||||
## |
||||
checkEnvironment() |
||||
{ |
||||
programs=(openssl curl printf echo sed awk od date pwd dirname) |
||||
for program in "${programs[@]}"; do |
||||
if [ ! -x "$(which $program)" ]; then |
||||
err "$program is required to run" |
||||
exit $INVALID_ENVIRONMENT_EXIT_CODE |
||||
fi |
||||
done |
||||
if [ ! -x "$(which sha256sum)" ]; then |
||||
if [ ! -x "$(which shasum)" ]; then |
||||
err "sha256sum or shasum is required to run" |
||||
exit $INVALID_ENVIRONMENT_EXIT_CODE |
||||
else |
||||
SHACMD="shasum -a 256 " |
||||
fi |
||||
else |
||||
SHACMD="sha256sum " |
||||
fi |
||||
} |
||||
|
||||
## |
||||
# Reads, validates and return aws secret stored in a file |
||||
# Arguments: |
||||
# $1 path to secret file |
||||
# Output: |
||||
# string AWS secret |
||||
## |
||||
processAWSSecretFile() { |
||||
local errStr="The Amazon AWS secret key must be 40 bytes long. Make sure that there is no carriage return at the end of line." |
||||
if ! [[ -f $1 ]]; then |
||||
err "The file $1 does not exist." |
||||
exit $INVALID_USER_DATA_EXIT_CODE |
||||
fi |
||||
|
||||
# limit file size to max 41 characters. 40 + potential null terminating character. |
||||
local fileSize="$(ls -l "$1" | awk '{ print $5 }')" |
||||
if [[ $fileSize -gt 41 ]]; then |
||||
err $errStr |
||||
exit $INVALID_USER_DATA_EXIT_CODE |
||||
fi |
||||
|
||||
secret=$(<$1) |
||||
# exact string size should be 40. |
||||
if [[ ${#secret} != 40 ]]; then |
||||
err $errStr |
||||
exit $INVALID_USER_DATA_EXIT_CODE |
||||
fi |
||||
echo $secret |
||||
} |
||||
|
||||
## |
||||
# Convert string to hex with max line size of 256 |
||||
# Arguments: |
||||
# $1 string to convert |
||||
# Returns: |
||||
# string hex |
||||
## |
||||
hex256() { |
||||
printf "$1" | od -A n -t x1 | sed ':a;N;$!ba;s/[\n ]//g' |
||||
} |
||||
|
||||
## |
||||
# Calculate sha256 hash |
||||
# Arguments: |
||||
# $1 string to hash |
||||
# Returns: |
||||
# string hash |
||||
## |
||||
sha256Hash() { |
||||
local output=$(printf "$1" | $SHACMD) |
||||
echo "${output%% *}" |
||||
} |
||||
|
||||
## |
||||
# Calculate sha256 hash of file |
||||
# Arguments: |
||||
# $1 file path |
||||
# Returns: |
||||
# string hash |
||||
## |
||||
sha256HashFile() { |
||||
local output=$($SHACMD $1) |
||||
echo "${output%% *}" |
||||
} |
||||
|
||||
## |
||||
# Generate HMAC signature using SHA256 |
||||
# Arguments: |
||||
# $1 signing key in hex |
||||
# $2 string data to sign |
||||
# Returns: |
||||
# string signature |
||||
## |
||||
hmac_sha256() { |
||||
printf "$2" | openssl dgst -binary -hex -sha256 -mac HMAC -macopt hexkey:$1 \ |
||||
| sed 's/^.* //' |
||||
} |
||||
|
||||
## |
||||
# Sign data using AWS Signature Version 4 |
||||
# Arguments: |
||||
# $1 AWS Secret Access Key |
||||
# $2 yyyymmdd |
||||
# $3 AWS Region |
||||
# $4 AWS Service |
||||
# $5 string data to sign |
||||
# Returns: |
||||
# signature |
||||
## |
||||
sign() { |
||||
local kSigning=$(hmac_sha256 $(hmac_sha256 $(hmac_sha256 \ |
||||
$(hmac_sha256 $(hex256 "AWS4$1") $2) $3) $4) "aws4_request") |
||||
hmac_sha256 "${kSigning}" "$5" |
||||
} |
||||
|
||||
## |
||||
# Get endpoint of specified region |
||||
# Arguments: |
||||
# $1 region |
||||
# Returns: |
||||
# amazon andpoint |
||||
## |
||||
convS3RegionToEndpoint() { |
||||
case "$1" in |
||||
us-east-1) echo "s3.amazonaws.com" |
||||
;; |
||||
*) echo s3-${1}.amazonaws.com |
||||
;; |
||||
esac |
||||
} |
||||
|
||||
## |
||||
# Perform request to S3 |
||||
# Uses the following Globals: |
||||
# METHOD string |
||||
# AWS_ACCESS_KEY_ID string |
||||
# AWS_SECRET_ACCESS_KEY string |
||||
# AWS_REGION string |
||||
# RESOURCE_PATH string |
||||
# FILE_TO_UPLOAD string |
||||
# CONTENT_TYPE string |
||||
# PUBLISH bool |
||||
# DEBUG bool |
||||
# VERBOSE bool |
||||
# INSECURE bool |
||||
## |
||||
performRequest() { |
||||
local timestamp=$(date -u "+%Y-%m-%d %H:%M:%S") |
||||
local isoTimestamp=$(date -ud "${timestamp}" "+%Y%m%dT%H%M%SZ") |
||||
local dateScope=$(date -ud "${timestamp}" "+%Y%m%d") |
||||
local host=$(convS3RegionToEndpoint "${AWS_REGION}") |
||||
|
||||
# Generate payload hash |
||||
if [[ $METHOD == "PUT" ]]; then |
||||
local payloadHash=$(sha256HashFile $FILE_TO_UPLOAD) |
||||
else |
||||
local payloadHash=$(sha256Hash "") |
||||
fi |
||||
|
||||
local cmd=("curl") |
||||
local headers= |
||||
local headerList= |
||||
|
||||
if [[ ${DEBUG} != true ]]; then |
||||
cmd+=("--fail") |
||||
fi |
||||
|
||||
if [[ ${VERBOSE} == true ]]; then |
||||
cmd+=("--verbose") |
||||
fi |
||||
|
||||
if [[ ${METHOD} == "PUT" ]]; then |
||||
cmd+=("-T" "${FILE_TO_UPLOAD}") |
||||
fi |
||||
cmd+=("-X" "${METHOD}") |
||||
|
||||
if [[ ${METHOD} == "PUT" && ! -z "${CONTENT_TYPE}" ]]; then |
||||
cmd+=("-H" "Content-Type: ${CONTENT_TYPE}") |
||||
headers+="content-type:${CONTENT_TYPE}\n" |
||||
headerList+="content-type;" |
||||
fi |
||||
|
||||
cmd+=("-H" "Host: ${host}") |
||||
headers+="host:${host}\n" |
||||
headerList+="host;" |
||||
|
||||
if [[ ${METHOD} == "PUT" && "${PUBLISH}" == true ]]; then |
||||
cmd+=("-H" "x-amz-acl: public-read") |
||||
headers+="x-amz-acl:public-read\n" |
||||
headerList+="x-amz-acl;" |
||||
fi |
||||
|
||||
cmd+=("-H" "x-amz-content-sha256: ${payloadHash}") |
||||
headers+="x-amz-content-sha256:${payloadHash}\n" |
||||
headerList+="x-amz-content-sha256;" |
||||
|
||||
cmd+=("-H" "x-amz-date: ${isoTimestamp}") |
||||
headers+="x-amz-date:${isoTimestamp}" |
||||
headerList+="x-amz-date" |
||||
|
||||
if [[ -n "${AWS_SECURITY_TOKEN}" ]]; then |
||||
cmd+=("-H" "x-amz-security-token: ${AWS_SECURITY_TOKEN}") |
||||
headers+="\nx-amz-security-token:${AWS_SECURITY_TOKEN}" |
||||
headerList+=";x-amz-security-token" |
||||
fi |
||||
|
||||
# Generate canonical request |
||||
local canonicalRequest="${METHOD} |
||||
${RESOURCE_PATH} |
||||
|
||||
${headers} |
||||
|
||||
${headerList} |
||||
${payloadHash}" |
||||
|
||||
# Generated request hash |
||||
local hashedRequest=$(sha256Hash "${canonicalRequest}") |
||||
|
||||
# Generate signing data |
||||
local stringToSign="AWS4-HMAC-SHA256 |
||||
${isoTimestamp} |
||||
${dateScope}/${AWS_REGION}/s3/aws4_request |
||||
${hashedRequest}" |
||||
|
||||
# Sign data |
||||
local signature=$(sign "${AWS_SECRET_ACCESS_KEY}" "${dateScope}" "${AWS_REGION}" \ |
||||
"s3" "${stringToSign}") |
||||
|
||||
local authorizationHeader="AWS4-HMAC-SHA256 Credential=${AWS_ACCESS_KEY_ID}/${dateScope}/${AWS_REGION}/s3/aws4_request, SignedHeaders=${headerList}, Signature=${signature}" |
||||
cmd+=("-H" "Authorization: ${authorizationHeader}") |
||||
|
||||
local protocol="https" |
||||
if [[ $INSECURE == true ]]; then |
||||
protocol="http" |
||||
fi |
||||
cmd+=("${protocol}://${host}${RESOURCE_PATH}") |
||||
|
||||
# Curl |
||||
"${cmd[@]}" |
||||
} |
@ -0,0 +1,104 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"os/exec" |
||||
"regexp" |
||||
"strings" |
||||
"time" |
||||
|
||||
errors "git.sequentialread.com/forest/pkg-errors" |
||||
|
||||
"git.sequentialread.com/forest/rootsystem/configuration" |
||||
"git.sequentialread.com/forest/rootsystem/objectStorage" |
||||
) |
||||
|
||||
func main() { |
||||
config, _, err := configuration.LoadConfiguration() |
||||
if err != nil { |
||||
panic(errors.Wrap(err, "host-key-poller failed because loadConfiguration() returned")) |
||||
} |
||||
|
||||
storage, err := objectStorage.InitializeObjectStorage(config, false) |
||||
if err != nil { |
||||
panic(errors.Wrap(err, "host-key-poller failed to initialize object storage")) |
||||
} |
||||
|
||||
iterations := 0 |
||||
for iterations < 60 { |
||||
iterations++ |
||||
|
||||
filename := fmt.Sprintf("rootsystem/known-hosts/%s", os.Args[1]) |
||||
fmt.Printf("polling for %s...\n", filename) |
||||
|
||||
file, notFound, err := storage.Get(filename) |
||||
|
||||
fmt.Printf("result: notFound: %t, err: %t\n", notFound, err != nil) |
||||
|
||||
if err != nil { |
||||
fmt.Printf("the error was: %s\n", err) |
||||
} |
||||
|
||||
if err == nil && !notFound { |
||||
lines := strings.Split(string(file.Content), "\n") |
||||
validLines := []string{} |
||||
ipAddress := "" |
||||
for _, line := range lines { |
||||
if len(strings.Trim(line, "\t \n\r")) > 10 { |
||||
fields := strings.Split(line, " ") |
||||
if len(fields) >= 3 { |
||||
ip := fields[0] |
||||
hostKeyType := fields[1] |
||||
base64PublicKey := fields[2] |
||||
ipValid := regexp.MustCompile("(\\d+\\.)+\\d+").FindString(ip) != "" |
||||
typeValid := (hostKeyType == "ecdsa-sha2-nistp256" || hostKeyType == "ssh-rsa" || hostKeyType == "ssh-ed25519") |
||||
base64Valid := regexp.MustCompile("[A-Za-z0-9+/=]+").FindString(base64PublicKey) != "" |
||||
|
||||
if ipValid && typeValid && base64Valid { |
||||
ipAddress = ip |
||||
validLines = append(validLines, fmt.Sprintf("%s %s %s", ip, hostKeyType, base64PublicKey)) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if len(validLines) > 0 { |
||||
fmt.Printf("Removing %s from %s:\n", ipAddress, configuration.KNOWN_HOSTS_FILE_NAME) |
||||
fmt.Printf("ssh-keygen -f %s -R %s\n", configuration.KNOWN_HOSTS_FILE_NAME, ipAddress) |
||||
|
||||
process := exec.Command("ssh-keygen", "-f", configuration.KNOWN_HOSTS_FILE_NAME, "-R", ipAddress) |
||||
err := process.Start() |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
err = process.Wait() |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
file, err := os.OpenFile(configuration.KNOWN_HOSTS_FILE_NAME, os.O_APPEND|os.O_WRONLY, 0600) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
defer file.Close() |
||||
|
||||
fmt.Printf("Writing to %s:\n", configuration.KNOWN_HOSTS_FILE_NAME) |
||||
for _, line := range validLines { |
||||
fmt.Println(line) |
||||
if _, err = file.WriteString(fmt.Sprintf("\n%s", line)); err != nil { |
||||
panic(err) |
||||
} |
||||
} |
||||
|
||||
os.Exit(0) |
||||
} |
||||
} |
||||
|
||||
time.Sleep(time.Second * time.Duration(5)) |
||||
} |
||||
|
||||
panic(errors.New("Timed Out")) |
||||
} |