[PYTHON] Essayez de créer votre propre AWS-SDK avec bash

Aperçu

J'ai créé AWS-SDK avec bash. AWS-AWS sera capable de gérer même les PC qui ne disposent pas d'un SDK ou d'un environnement de programmation.

Lors de la réalisation, j'essaye d'observer les conditions suivantes.

Les articles peuvent être ouverts et fermés pour chaque service, veuillez donc lire uniquement les services dont vous avez besoin.

Diagramme

draw_1.png

Le produit fini

Comme il n'est pas possible de vérifier le fonctionnement de toutes les fonctions du SDK, nous vérifierons uniquement le fonctionnement ci-dessous dans cet article.

Avant utilisation: préparer le profil

Lorsque vous l'utilisez, veuillez créer des informations de profil dans ~ / .aws / credentials. Le format est du texte et aucune extension n'est requise.

~/.aws/credentials


[default]
aws_access_key_id = AKIA**************************
aws_secret_access_key = *****************************

Contrôle d'opération: manipuler les données DynamoDB

<détails>

Procédure de fonctionnement de DynamoDB (cliquez pour ouvrir) </ summary>

Obtenir des données de DynamoDB


./aws-sdk-bash.sh "default" "ap-northeast-1" "dynamodb" "/" "" \
"content-type:application/x-amz-json-1.0;host:@;x-amz-date:@;x-amz-target:DynamoDB_20120810.GetItem" \
"{\"TableName\": \"target_table\", \"Key\": {\"id\": {\"S\": \"key\"}}}"

{"Item":{"entity":{"S":"string_data"},"id":{"S":"key"}}}

** Lorsque la même demande est écrite dans AWS-SDK (boto3) **

boto3


from boto3 import Session
Session(
    profile_name = "default", 
    region_name = "ap-northeast-1"
).client(
    service_name = "dynamodb"
).get_item(
    TableName = "target_table",
    Key = {"id" : {"S" : "key"}}
)

** Confirmez que les données peuvent être enregistrées et analysées en modifiant l'argument **

Autres opérations de DynamoDB


#Entrer des données
./aws-sdk-bash.sh "default" "ap-northeast-1" "dynamodb" "/" "" \
"content-type:application/x-amz-json-1.0;host:@;x-amz-date:@;x-amz-target:DynamoDB_20120810.PutItem" \
"{\"TableName\": \"target_table\", \"Item\": {\"id\": {\"S\": \"newData\"}, \"entity\":{\"S\":\"new_string_data\"}}}"

{}

#Après avoir saisi les données, vérifiez que le nombre de cas augmente avec Scan
./aws-sdk-bash.sh "default" "ap-northeast-1" "dynamodb" "/" "" \
"content-type:application/x-amz-json-1.0;host:@;x-amz-date:@;x-amz-target:DynamoDB_20120810.Scan" \
"{\"TableName\": \"target_table\"}"

{"Count":2,"Items":[{"entity":{"S":"new_string_data"},"id":{"S":"newData"}},{"entity":{"S":"string_data"},"id":{"S":"key"}}],"ScannedCount":2}

** Demander les détails des paramètres **

Le nom du paramètre Contenu de l'exemple de demande ci-dessus Remarques
Nom de profil default Nom de la certification
Région ap-northeast-1 Région情報
Nom du service dynamodb Nom du service。DynamoDB
Chemin URI / Chemin du point de terminaison, chemin racine dans DynamoDB
Requête URL Non utilisé dans DynamoDB
En-tête HTTP content-type:application/x-amz-json-1.0;
host:@;
x-amz-date:@;
x-amz-target:DynamoDB_20120810.GetItem
@Est donné côté script
x-amz-Vous pouvez spécifier le processus à exécuter par cible.
Obtenir (GetItem)
Ajouter (PutItem)
Scan… etc
Charge utile POST {"TableName":"target_table", "Key": {"id" : "S" : "key"}}

Contrôle de fonctionnement: exécutez Lambda directement

Procédure de fonctionnement de Lambda (cliquez pour ouvrir)

Exécutez Lambda


./aws-sdk-bash.sh "default" "ap-northeast-1" "lambda" "/2015-03-31/functions/sample_lambda/invocations" "" \
"host:@;x-amz-content-sha256:@;x-amz-date:@;x-amz-invocation-type:RequestResponse;x-amz-user-agent:aws-sdk-js/2.668.0 callback" \
"{\"Message\":\"Hello\"}"

{"statusCode": 200, "body": "\"Hello from Lambda! I am SAMPLE\""}

** Lorsque la même demande est écrite dans AWS-SDK (boto3) **

boto3


from boto3 import Session
import json
Session(
    profile_name = "default", 
    region_name = "ap-northeast-1"
).client(
    service_name = "lambda"
).invoke(
    FunctionName = "sample_lambda",
    InvocationType = "RequestResponse",
    Payload = json.dumps({"Message" : "Hello"})
)

** Paramètres de demande **

Le nom du paramètre Contenu de l'exemple de demande ci-dessus Remarques
Profil default Nom de la certification
Région ap-northeast-1 Région情報
Nom du service lambda Nom du service。Lambda
Chemin URI /2015-03-31/functions/sample_lambda/invocations Opération à effectuer
Nom Lambda "échantillon"_Émettez la commande "invoke" à "lambda"
Requête URL Non utilisé dans Lambda
En-tête HTTP host:@;
x-amz-content-sha256:@;
x-amz-date:@;
x-amz-invocation-type:RequestResponse;
x-amz-user-agent:aws-sdk-js/2.668.0 callback
@Est donné côté script
Spécifiez RequestResponse pour le traitement synchrone avec réponse
UA emprunte la version JavaScript de UA
Charge utile POST {"Message":"Hello"}

Contrôle de fonctionnement: manipuler les données SQS

<détails>

Procédure de fonctionnement de SQS (cliquez pour ouvrir) </ summary>

Exécutez SQS


#Envoyer le message
./aws-sdk-bash.sh "default" "ap-northeast-1" "sqs" "/" "" \
"host:@;x-amz-content-sha256:@;x-amz-date:@;x-amz-user-agent:aws-sdk-js/2.668.0 callback" \
"Action=SendMessage&MessageBody=%7B%22id%22%3A%22NewMessage%22%7D&QueueUrl=https%3A%2F%2Fsqs.ap-northeast-1.amazonaws.com%2F***********************%2Fsqs-send-request-test-0424&Version=2012-11-05"

<?xml version="1.0"?><SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><SendMessageResult><MessageId>013a849d-f344-4d90-a6be-e37302c6b029</MessageId><MD5OfMessageBody>abc832604cb20908715bca6f197c8945</MD5OfMessageBody></SendMessageResult><ResponseMetadata><RequestId>01e07779-a593-5162-b698-2050d59e1524</RequestId></ResponseMetadata></SendMessageResponse>

#Recevez le message que vous avez envoyé
./aws-sdk-bash.sh "default" "ap-northeast-1" "sqs" "/" "" \
"host:@;x-amz-content-sha256:@;x-amz-date:@;x-amz-user-agent:aws-sdk-js/2.668.0 callback" \
"Action=ReceiveMessage&QueueUrl=https%3A%2F%2Fsqs.ap-northeast-1.amazonaws.com%2F*****************%2Fsqs-send-request-test-0424&Version=2012-11-05"

<?xml version="1.0"?><ReceiveMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><ReceiveMessageResult><Message><MessageId>6335c486-d1b6-4478-84c4-40b92f5d655b</MessageId><ReceiptHandle>***********</ReceiptHandle><MD5OfBody>abc832604cb20908715bca6f197c8945</MD5OfBody><Body>{&quot;id&quot;:&quot;NewMessage&quot;}</Body></Message></ReceiveMessageResult><ResponseMetadata><RequestId>9e05f85b-4a27-5d6f-97c4-af723bb68a70</RequestId></ResponseMetadata></ReceiveMessageResponse>

** Lors de l'envoi d'un message avec boto3 **

from boto3 import Session
import json
Session(
    profile_name = "default", 
    region_name = "ap-northeast-1"
).client(
    service_name = "sqs"
).send_message(
    QueueUrl = "https://sqs.ap-northeast-1.amazonaws.com/**************/sqs-send-request-test-0424",
    MessageBody = json.dumps({"id": "NewMessage"})
)

** Paramètres de demande **

Le nom du paramètre Contenu de l'exemple de demande ci-dessus Remarques
Profil default Nom de la certification
Région ap-northeast-1 Région情報
Nom du service sqs Nom du service。SQS
Chemin URI / Non utilisé dans SQS
Requête URL Non utilisé dans SQS
En-tête HTTP host:@;
x-amz-content-sha256:@;
x-amz-date:@;
x-amz-user-agent:aws-sdk-js/2.668.0 callback
@Est donné côté script
UA emprunte la version JavaScript de UA
Charge utile POST Action=SendMessage&MessageBody=%7B%22id%22%3A%22NewMessage%22%7D&QueueUrl=https%3A%2F%2Fsqs.ap-northeast-1.amazonaws.com%2F***********************%2Fsqs-send-request-test-0424&Version=2012-11-05 SQS est soumis au format de données de formulaire.
Utilisez Action pour changer d'opérations telles que l'envoi et la réception.

Contrôle d'opération: Obtenez vos propres informations de profil de STS

<détails>

Étapes pour faire fonctionner STS (cliquez pour ouvrir) </ summary>

Exécutez STS


#Obtenez vos propres informations
./aws-sdk-bash.sh "default" "ap-northeast-1" "sts" "/" "" \
"host:@;x-amz-content-sha256:@;x-amz-date:@;x-amz-user-agent:aws-sdk-js/2.668.0 callback" \
"Action=GetCallerIdentity&Version=2011-06-15"

<GetCallerIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
  <GetCallerIdentityResult>
    <Arn>arn:aws:iam::*****************:user/**************</Arn>
    <UserId>*****************</UserId>
    <Account>*****************</Account>
  </GetCallerIdentityResult>
  <ResponseMetadata>
    <RequestId>1703851c-5b55-49b5-8bcf-130ab4dbb6f2</RequestId>
  </ResponseMetadata>
</GetCallerIdentityResponse>

** Lorsque le même processus est écrit en boto3 **

from boto3 import Session
Session(
    profile_name = "default", 
    region_name = "ap-northeast-1"
).client(
    service_name = "sts"
).get_caller_identity()

** Paramètres de demande **

Le nom du paramètre Contenu de l'exemple de demande ci-dessus Remarques
Profil default Nom de la certification
Région ap-northeast-1 Région情報
Nom du service sts Nom du service。STS
Chemin URI / Non utilisé dans SQS
Requête URL Non utilisé dans SQS
En-tête HTTP host:@;
x-amz-content-sha256:@;
x-amz-date:@;
x-amz-user-agent:aws-sdk-js/2.668.0 callback
@Est donné côté script
UA emprunte la version JavaScript de UA
Charge utile POST Action=GetCallerIdentity&Version=2011-06-15 STS est soumis au format de données de formulaire.
Changez d'opération avec Action.

Code source

Si vous souhaitez l'exécuter, enregistrez-le à n'importe quel emplacement sous le nom de fichier aws-sdk-bash.sh. Pour la commande à exécuter, reportez-vous à "Contrôle de fonctionnement".

aws-sdk-bash.sh


#!/bin/bash

#Le chemin du profil est fixe
CREDENTIALS_FILE=~/.aws/credentials
#L'algorithme est la signature v4, SHA256 de hmac
ALGORITHM='AWS4-HMAC-SHA256'

#Arguments de script
_INPUT_PROFILE_NAME=$1
_INPUT_REGION=$2
_INPUT_SERVICE=$3
_INPUT_CANONICAL_URI=$4
_INPUT_CANONICAL_QUERY_STRING=$5
_INPUT_OPTIONAL_HEADERS=$6
_INPUT_PAYLOAD=$7

#Créer un point de terminaison
METHOD=POST
PROTOCOL=https
HOST_NAME=${_INPUT_SERVICE}.${_INPUT_REGION}.amazonaws.com

# .Obtenir des informations de profil à partir du fichier aws
#Chemin du profil d'entrée, nom du profil, nom de la clé de profil, nombre de lignes pour lire le fichier
get_credentials () {
    _CREDENTIALS_FILE=$1; _PROFILE_NAME=$2; _KEY_NAME=$3; _READ_LENGTH=$4;

    # PROFILE_Obtenez le numéro de ligne de NAME
    PROFILE_IDX=`nl $_CREDENTIALS_FILE | grep $_PROFILE_NAME | head -n 1 | awk '{print $1}'`
    PROFILE_IDX_END=`expr $PROFILE_IDX + $_READ_LENGTH`

    #Obtenir l'ID de la clé d'accès
    RESULT=`cat $CREDENTIALS_FILE | sed -n "${PROFILE_IDX},${PROFILE_IDX_END}p" | grep "=" | grep ${_KEY_NAME} | \
    tr -d " " | sed "s/=/ /g" | awk '{print $2}' | \
    head -n 1`

    echo -n $RESULT
}

#Créer un hachage avec SHA256
#Message d'entrée: fichier, clé: aucun
#Hachage de sortie: format hexadécimal
create_digest_from_file () {
    cat $1 | openssl dgst -sha256 | grep stdin | awk '{print $2}'
}

# HMAC-Créer un hachage avec SHA256
#Message d'entrée: texte, clé: texte
#Hachage de sortie: format hexadécimal
sign_from_string () {
    echo -n $2 | openssl dgst -sha256 -hmac $1 | grep stdin | awk '{print $2}'
}

# HMAC-Créer un hachage avec SHA256
#Message d'entrée: texte, clé: format hexadécimal
#Hachage de sortie: format hexadécimal
sign_from_string_with_hex_key () {
    echo -n $2 | openssl dgst -sha256 -mac hmac -macopt hexkey:$1 | grep stdin | awk '{print $2}'
}

# HMAC-Créer un hachage avec SHA256
#Message d'entrée: fichier, clé: format hexadécimal
#Hachage de sortie: format hexadécimal
sign_from_file_with_hex_key () {
    cat $2 | openssl dgst -sha256 -mac hmac -macopt hexkey:$1 | grep stdin | awk '{print $2}'
}

#Informations de base HMAC de la signature v4 (ID de la clé d'accès, date et heure de transmission, région, nom du service)-Hash avec SHA256
get_signature_key () {
    TEMP_DATE=`sign_from_string AWS4$1 $2`
    TEMP_REGION=`sign_from_string_with_hex_key $TEMP_DATE $3`
    TEMP_SERVICE=`sign_from_string_with_hex_key $TEMP_REGION $4`
    sign_from_string_with_hex_key $TEMP_SERVICE 'aws4_request'
}

#Obtenir l'ID de la clé d'accès
ACCESS_KEY_ID=`get_credentials $CREDENTIALS_FILE ${_INPUT_PROFILE_NAME} aws_access_key_id 2`

#Obtenez une clé d'accès secrète
SECRET_ACCESS_KEY=`get_credentials $CREDENTIALS_FILE ${_INPUT_PROFILE_NAME} aws_secret_access_key 2`

#Obtenir la date et l'heure UTC (exemple de format: 2020/12/31T12:34:À 50 AMZ_DATE:20201231T123450Z DATE_STAMP:20201231)
UTC_DATE=`date -Iseconds -u | sed "s/+/ /g" | awk '{print $1 "Z"}'`
AMZ_DATE=`echo -n $UTC_DATE | sed "s/-//g" | sed "s/://g"`
DATE_STAMP=`echo -n $UTC_DATE | sed "s/-//g" | sed "s/T/ /g" | awk '{print $1}'`

#Créer un fichier temporaire, supprimer le fichier temporaire à la fin
TEMP_HEADERS=`mktemp`
TEMP_CANONICAL_REQUEST=`mktemp`
TEMP_STRING_TO_SIGN=`mktemp`
TEMP_PAYLOAD=`mktemp`
trap "rm -f $TEMP_HEADERS; rm -f $TEMP_CANONICAL_REQUEST; rm -f $TEMP_STRING_TO_SIGN; rm -f $TEMP_PAYLOAD" EXIT

#Copiez la charge utile dans un fichier temporaire
echo -n ${_INPUT_PAYLOAD} > $TEMP_PAYLOAD

#Créer un hachage SHA256 (sans clé) à partir des données BODY à envoyer
PAYLOAD_HASH=`create_digest_from_file $TEMP_PAYLOAD`

#Définir l'en-tête d'envoi
echo -n "${_INPUT_OPTIONAL_HEADERS}" | sed "s#x-amz-content-sha256:@#x-amz-content-sha256:${PAYLOAD_HASH}#" | sed "s#host:@#host:${HOST_NAME}#" | sed "s#x-amz-date:@#x-amz-date:${AMZ_DATE}#" | xargs -d ";" -r -I @ echo @ >> $TEMP_HEADERS
SIGNED_HEADERS=`echo -n "${_INPUT_OPTIONAL_HEADERS}" | xargs -d ";" -r -I @ echo ";@" | sed 's/:.*//'`
SIGNED_HEADERS=`echo -n $SIGNED_HEADERS | sed 's/ //g' | sed 's/^;//'`

#Faire une demande canonique
#Normaliser les informations de demande
#Informations de référence: Tâche 1:Faire une demande légitime pour la version 4 signée
# https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-create-canonical-request.html
echo $METHOD > $TEMP_CANONICAL_REQUEST
echo $_INPUT_CANONICAL_URI >> $TEMP_CANONICAL_REQUEST
echo $_INPUT_CANONICAL_QUERY_STRING >> $TEMP_CANONICAL_REQUEST
cat $TEMP_HEADERS >> $TEMP_CANONICAL_REQUEST
echo "" >> $TEMP_CANONICAL_REQUEST
echo $SIGNED_HEADERS >> $TEMP_CANONICAL_REQUEST
echo -n $PAYLOAD_HASH >> $TEMP_CANONICAL_REQUEST

#Créer une chaîne de signature
#Informations de référence: Tâche 2:Créer une chaîne de signature version 4 de signature
# https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-create-string-to-sign.html
CANONICAL_REQUEST_HASH=`create_digest_from_file $TEMP_CANONICAL_REQUEST`
CREDENTIAL_SCOPE=${DATE_STAMP}/${_INPUT_REGION}/${_INPUT_SERVICE}/"aws4_request"

#Définir l'algorithme de signature et la portée de la signature
echo ${ALGORITHM} > $TEMP_STRING_TO_SIGN
echo ${AMZ_DATE} >> $TEMP_STRING_TO_SIGN
echo ${CREDENTIAL_SCOPE} >> $TEMP_STRING_TO_SIGN
echo -n ${CANONICAL_REQUEST_HASH} >> $TEMP_STRING_TO_SIGN

#Calculer la signature pour la signature
#Informations de référence: Tâche 3:Signature AWS Sign Calculate version 4
# https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-calculate-signature.html
SIGNING_KEY=`get_signature_key ${SECRET_ACCESS_KEY} ${DATE_STAMP} ${_INPUT_REGION} ${_INPUT_SERVICE}`
SIGNATURE=`sign_from_file_with_hex_key ${SIGNING_KEY} ${TEMP_STRING_TO_SIGN}`

#Définir la signature dans l'en-tête de la requête HTTP
#Informations de référence: Tâche 4:Ajouter une signature à la requête HTTP
# https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-add-signature-to-request.html
AUTHORIZATION_HEADER="${ALGORITHM} Credential=${ACCESS_KEY_ID}/${CREDENTIAL_SCOPE}, SignedHeaders=${SIGNED_HEADERS}, Signature=${SIGNATURE}"

#Envoyez une requête HTTP.
QUERY_STRING=${_INPUT_CANONICAL_QUERY_STRING}
if [ ! $QUERY_STRING = "" ]; then
    QUERY_STRING="?${QUERY_STRING}"
fi
curl -s -X POST ${PROTOCOL}://${HOST_NAME}${_INPUT_CANONICAL_URI}${QUERY_STRING} -d @$TEMP_PAYLOAD -H @$TEMP_HEADERS -H "Authorization: ${AUTHORIZATION_HEADER}"

Explication du code source

Le flux de traitement est le suivant. Il existe différents SDK pour différentes langues, mais si vous implémentez uniquement ces quatre, vous pouvez faire la même chose que l'AWS-SDK.

\def\de{\unicode[serif]{x306E}}
\bbox[8px, border: 2px solid gray]{\rlap{\tt 1.\informations de profil quad\Avoir}\hspace{80mm}}
\triangledown
\def\de{\unicode[serif]{x306E}}
\bbox[8px, border: 2px solid gray]{\rlap{\tt 2.\paramètre quad\Obtenez et créez}\hspace{80mm}}
\triangledown
\bbox[8px, border: 2px solid gray]{\rlap{\tt 3.\Paramètre quadruple de hachage avec SHA256}\hspace{80mm}}
\triangledown
\bbox[8px, border: 2px solid gray]{\rlap{\tt 4.\Envoyer une requête HTTP avec quadruple curl}\hspace{80mm}}

Pour la signature de la version 4, consultez le document officiel AWS [«Exemple de processus de signature de version 4 entièrement signé (Python)»](https://docs.aws.amazon.com/ja_jp/general/latest/gr/sigv4-signed -request-examples.html) Veuillez vous référer à.

Ci-après, chaque processus sera expliqué.

1. Acquisition des informations de profil

C'est le processus pour obtenir des informations de profil à partir de ~ / .aws / credentials.

\def\de{\unicode[serif]{x306E}}
\begin{array}{l|l}
\hline 
commander&Objectif\\
\hline 
{\tt nl} &numéro de ligne+Fichier\Affiche le contenu de.\\
&numéro de ligne\C'est un chat qui sort.\\
\hdashline 
{\tt sed\;\text{-n}} &Ligne spécifiée\Obtenez le texte de.\\
\hline 
\end{array}

Utilisez "nl + grep profile name" pour obtenir le nombre de lignes du nom du profil à obtenir. "Sed -n" prendra la ligne après le nom du profil, alors prenez l'ID de clé d'accès et la clé d'accès secrète à partir de là.

aws-sdk-bash.sh_Obtenir des informations de signature


# .Obtenir des informations de profil à partir du fichier aws
#Chemin d'entrée du profil, nom du profil, nom de la clé de profil, nombre de lignes pour lire le profil
get_credentials () {
    _CREDENTIALS_FILE=$1; _PROFILE_NAME=$2; _KEY_NAME=$3; _READ_LENGTH=$4;

    # PROFILE_Obtenez le numéro de ligne de NAME
    PROFILE_IDX=`nl $_CREDENTIALS_FILE | grep $_PROFILE_NAME | head -n 1 | awk '{print $1}'`
    PROFILE_IDX_END=`expr $PROFILE_IDX + $_READ_LENGTH`

    #Obtenir l'ID de la clé d'accès
    RESULT=`cat $CREDENTIALS_FILE | sed -n "${PROFILE_IDX},${PROFILE_IDX_END}p" | grep "=" | grep ${_KEY_NAME} | \
    tr -d " " | sed "s/=/ /g" | awk '{print $2}' | \
    head -n 1`

    echo -n $RESULT
}

aws-sdk-bash.sh_Votre interlocuteur


#Obtenir l'ID de la clé d'accès
ACCESS_KEY_ID=`get_credentials $CREDENTIALS_FILE ${_INPUT_PROFILE_NAME} aws_access_key_id 2`

#Obtenez une clé d'accès secrète
SECRET_ACCESS_KEY=`get_credentials $CREDENTIALS_FILE ${_INPUT_PROFILE_NAME} aws_secret_access_key 2`

2. Obtenir et créer des paramètres

** Obtenez la date et l'heure **

Obtenez la date et l'heure en UTC. Créez une chaîne dans un format qui inclut les heures, les minutes et les secondes, et un format qui n'inclut pas les heures, les minutes et les secondes.

\def\de{\unicode[serif]{x306E}}
\begin{array}{l|l}
\hline 
valeur&format\\
\hline 
{\tt \text{AMZ_DATE}} & {\tt YYYYMMDDTHHMMSS}\Spécifiez au format.\\
&Derrière{\tt UTC}Pointer vers{\tt Z}Je vais mettre.\\
&Colon, trait d'union\N'incluez pas de symboles tels que.\\
\hdashline 
{\tt \text{DATE_STAMP}} & {\tt YYYYMMDD}\Spécifiez au format.\\
&Précisez uniquement la date.\\
&Colon, trait d'union\N'incluez pas de symboles tels que.\\
\hline 
\end{array}

aws-sdk-bash.sh_Obtenir la date et l'heure UTC


#Obtenir la date et l'heure UTC (exemple de format: 2020/12/31T12:34:À 50 AMZ_DATE:20201231T123450Z DATE_STAMP:20201231)
UTC_DATE=`date -Iseconds -u | sed "s/+/ /g" | awk '{print $1 "Z"}'`
AMZ_DATE=`echo -n $UTC_DATE | sed "s/-//g" | sed "s/://g"`
DATE_STAMP=`echo -n $UTC_DATE | sed "s/-//g" | sed "s/T/ /g" | awk '{print $1}'`

** Traiter le texte **

La chaîne de caractères est écrite dans un fichier temporaire et gérée. Les fichiers temporaires sont supprimés à la fin du processus.

Vous pouvez le gérer avec des variables bash, mais il est plus facile à implémenter si vous gérez des chaînes dans des fichiers. Pour les informations de signature, les lignes vides, les sauts de ligne à la fin et l'ordre d'apparition des données sont strictement déterminés, et si même un se décale, la signature ne passera pas.

\def\de{\unicode[serif]{x306E}}
\begin{array}{l|l}
\hline 
commander&Objectif\\
\hline 
{\tt mktemp} & /Créez un fichier temporaire dans tmp.\\
&Les noms de fichiers sont donnés sans duplication\\
&Les droits d'accès sont également définis de manière appropriée.\\
\hdashline 
{\tt trap} &spécifique\La commande est exécutée au moment de.\\
&Supprimez le fichier temporaire à la fin du processus.\\
\hline 
\end{array}

aws-sdk-bash.sh_Créer un fichier temporaire


#Créer un fichier temporaire, supprimer le fichier temporaire à la fin
TEMP_HEADERS=`mktemp`
TEMP_CANONICAL_REQUEST=`mktemp`
TEMP_STRING_TO_SIGN=`mktemp`
TEMP_PAYLOAD=`mktemp`
trap "rm -f $TEMP_HEADERS; rm -f $TEMP_CANONICAL_REQUEST; rm -f $TEMP_STRING_TO_SIGN; rm -f $TEMP_PAYLOAD" EXIT

** Remplacement des paramètres **

Il existe certains paramètres dont l'utilisateur n'a pas connaissance lors de la création d'une demande. Ces paramètres sont définis côté script en omettant la valeur avec @.

\begin{array}{ll}
Paramètres définis par l'utilisateur& {\tt \text{x-amz-date:@}} \\
Paramètres réellement envoyés& {\tt \text{x-amz-date:20200504T145432Z}}\\
& \\
\end{array}
\def\de{\unicode[serif]{x306E}}
\begin{array}{l|l}
\hline 
entête\clé de&Valeur à définir\\
\hline 
{\tt \text{x-amz-content-sha256}} &charge utile\Valeur de hachage de\\
\hdashline 
{\tt host} & {\tt point de terminaison AWS\URL}\\
\hdashline 
{\tt \text{x-amz-date}}  &Date et heure de la demande\\
\hline 
\end{array}

aws-sdk-bash.sh_Définir l'en-tête


#Créer un hachage SHA256 (sans clé) à partir des données BODY à envoyer
PAYLOAD_HASH=`create_digest_from_file $TEMP_PAYLOAD`

#Définir l'en-tête d'envoi
echo -n "${_INPUT_OPTIONAL_HEADERS}" | sed "s#x-amz-content-sha256:@#x-amz-content-sha256:${PAYLOAD_HASH}#" | sed "s#host:@#host:${HOST_NAME}#" | sed "s#x-amz-date:@#x-amz-date:${AMZ_DATE}#" | xargs -d ";" -r -I @ echo @ >> $TEMP_HEADERS
SIGNED_HEADERS=`echo -n "${_INPUT_OPTIONAL_HEADERS}" | xargs -d ";" -r -I @ echo ";@" | sed 's/:.*//'`
SIGNED_HEADERS=`echo -n $SIGNED_HEADERS | sed 's/ //g' | sed 's/^;//'`

3. Hashing

Pour obtenir HMAC-SHA256, écrivez comme suit en Python.

HMAC-Obtenez SHA256


def sign(key, msg):
    return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()

def getSignatureKey(key, dateStamp, regionName, serviceName):
    kDate = sign(("AWS4" + key).encode("utf-8"), dateStamp)
    kRegion = sign(kDate, regionName)
    kService = sign(kRegion, serviceName)
    kSigning = sign(kService, "aws4_request")
    return kSigning

Pour faire de même avec bash, utilisez openssl.

\def\de{\unicode[serif]{x306E}}
\begin{array}{l|l}
\hline 
commander&Objectif\\
\hline 
{\tt openssl\;dgst\;\text{-}sha256} &Texte{\tt SHA256}Hash avec.\\
&Le résultat sera un nombre hexadécimal.\\
\hdashline 
{\tt openssl\;dgst\;\text{-}sha256} &Texte{\tt SHA256}Hash avec.\\
\qquad{\tt \text{-}hmac\;(key)} &Texte brut\Spécifiez la clé de.\\
&Le résultat sera un nombre hexadécimal.\\
\hdashline 
{\tt openssl\;dgst\;\text{-}sha256} &Texte{\tt SHA256}Hash avec.\\
\qquad{\tt \text{-}mac\;hmac} &Hexadécimal\Spécifiez la clé de.\\
\qquad{\tt \text{-}macopt\;hexkey:(key)}&Le résultat sera un nombre hexadécimal.\\
\hline 
\end{array}

aws-sdk-bash.sh_Hashing


#Créer un hachage avec SHA256
#Message d'entrée: fichier, clé: aucun
#Hachage de sortie: format hexadécimal
create_digest_from_file () {
    cat $1 | openssl dgst -sha256 | grep stdin | awk '{print $2}'
}

# HMAC-Créer un hachage avec SHA256
#Message d'entrée: texte, clé: texte
#Hachage de sortie: format hexadécimal
sign_from_string () {
    echo -n $2 | openssl dgst -sha256 -hmac $1 | grep stdin | awk '{print $2}'
}

# HMAC-Créer un hachage avec SHA256
#Message d'entrée: texte, clé: format hexadécimal
#Hachage de sortie: format hexadécimal
sign_from_string_with_hex_key () {
    echo -n $2 | openssl dgst -sha256 -mac hmac -macopt hexkey:$1 | grep stdin | awk '{print $2}'
}

# HMAC-Créer un hachage avec SHA256
#Message d'entrée: fichier, clé: format hexadécimal
#Hachage de sortie: format hexadécimal
sign_from_file_with_hex_key () {
    cat $2 | openssl dgst -sha256 -mac hmac -macopt hexkey:$1 | grep stdin | awk '{print $2}'
}

#Informations de base HMAC de la signature v4 (ID de la clé d'accès, date et heure de transmission, région, nom du service)-Hash avec SHA256
#Même processus que getSignatureKey en Python
get_signature_key () {
    TEMP_DATE=`sign_from_string AWS4$1 $2`
    TEMP_REGION=`sign_from_string_with_hex_key $TEMP_DATE $3`
    TEMP_SERVICE=`sign_from_string_with_hex_key $TEMP_REGION $4`
    sign_from_string_with_hex_key $TEMP_SERVICE 'aws4_request'
}

Comment vérifier la demande AWS-SDK

Les formats des charges utiles et des en-têtes lancés par l'AWS-SDK varient d'un service à l'autre. Il n'y a pas de documentation officielle, vous devez donc la rechercher vous-même.

un service Comment spécifier la méthode charge utile
Lambda Chemin URL JSON
DynamoDB entête JSON
SQS charge utile Format de formulaire
STS charge utile Format de formulaire

Comment vérifier avec boto3 + Wireshark

Si vous communiquez tel quel, il sera crypté, je vais donc ajouter un peu de travail.

Désactivez le cryptage et passez à la communication HTTP


import boto3
client = boto3.client("dynamodb", use_ssl = False)

print(client.get_item(TableName = "target_table", Key = {"id" : {"S":"key"}}))

Si use_ssl est défini sur False, il sera envoyé au port 80. Puisqu'il communique en texte brut, il peut être lu par Wireshark.

capture_1.png

Si vous regardez Wireshark, vous pouvez voir que les données que nous envoyons sont les suivantes.

texte


POST / HTTP/1.1
Host: dynamodb.ap-northeast-1.amazonaws.com
Accept-Encoding: identity
X-Amz-Target: DynamoDB_20120810.GetItem
Content-Type: application/x-amz-json-1.0
User-Agent: Boto3/1.12.43 Python/3.8.2 Windows/10 Botocore/1.15.43
X-Amz-Date: 20200501T213154Z
Authorization: AWS4-HMAC-SHA256 Credential=AKIA**********/20200501/ap-northeast-1/dynamodb/aws4_request, SignedHeaders=content-type;host;x-amz-date;x-amz-target, Signature=***********************************************************
Content-Length: 58

{"TableName": "target_table", "Key": {"id": {"S": "key"}}}

C'est OK si vous définissez les données de sorte que la même demande soit envoyée.

Notez que use_ssl ne peut pas être utilisé avec certains services. Par exemple, Lambda et MQTT. Si vous essayez de vous connecter au port 80 avec un service qui ne prend en charge que HTTPS, il expirera sans réponse.

Comment vérifier avec la fonction de vérification du navigateur

Si vous souhaitez voir la charge utile dans un service qui nécessite SSL, utilisez la version javascript du SDK.

test.html


<script src="https://sdk.amazonaws.com/js/aws-sdk-2.668.0.min.js"></script>
<script type="text/javascript">
    AWS.config.update({
        accessKeyId : 'AKIA******************',
        secretAccessKey : '**********************************'
    });
    AWS.config.region = 'ap-northeast-1';
    
    let lambda = new AWS.Lambda();
    let params = {
        FunctionName : 'sample_lambda',
        InvocationType : 'RequestResponse',
        Payload : JSON.stringify({
            "Message" : "Hello"
        })
    };
    
    lambda.invoke(params, (err, data) => console.log(JSON.parse(data.Payload)));
</script>

Après avoir écrit le processus que vous souhaitez archiver dans le fichier HTML, ouvrez-le dans le navigateur. Avec Chrome, vous pouvez vérifier les données de communication réseau en cliquant avec le bouton droit de la souris et en ouvrant «Vérifier» dans le navigateur.

lambda.png

Il existe certaines différences, telles que l'inclusion de données spécifiques au navigateur et nécessitant parfois CORS, mais nous avons toutes les données nécessaires. En référence à cela, c'est OK si vous définissez la même demande de vol.

Recommended Posts