AWS S3 hat eine "signierte URL". SQS kann etwas Ähnliches wie diese Funktion tun.
Angenommen, Sie möchten ein solches System erstellen.
Betrachten Sie die Konfiguration in AWS.
** <Konfiguration A: API-Gateway + Lambda> **
Lambda + API Gateway hat den Ruf, billig zu sein, kann jedoch bei der Bearbeitung einer großen Anzahl von Anfragen recht teuer sein.
Es ist eine grobe Berechnung, aber wenn es 172,8 Millionen Anfragen pro Tag gibt, ist die Gebühr für das Sammeln von Daten wie folgt.
Bedienung | Preis pro Million Anfragen | Tägliche Gebühr | Bedingungen |
---|---|---|---|
Lambda | Kommt auf die Bedingungen an | 387 USD | Durchschnittliche 1-Sekunden-Verarbeitung, Speicherzuweisung 128 MB |
Api Gateway | 4.25 USD | 731 USD | REST API |
SQS | 0.4 USD | 69 USD |
Gesamt: 1187 USD pro Tag
Mit Lambda-Verzögerungen, WAF, CloudFront, Authentifizierung und mehr geht es sogar noch höher.
** <Konfiguration B: AWS IoT + Rule Engine + SQS> **
Der Preis ist niedriger, wenn die Konfiguration mit der Regelengine von AWS IoT auf SQS übertragen werden soll. Aber dieses mal ...
Bedienung | Preis pro Million Anfragen | Tägliche Gebühr | Bedingungen |
---|---|---|---|
AWS IoT | Senden: 1.2 USD Regel: 0.18 USD Aktion: 0.18 USD |
268 USD | Regel+Handeln Sie |
SQS | 0.4 USD | 69 USD |
Gesamt: 337 USD pro Tag
Diesmal ist MQTT aufgrund des Ports nicht möglich, und WebSocket ist auch aufgrund der Terminalseite nicht möglich.
**
Übrigens, wenn Sie direkt vom Terminal an SQS senden können, kostet es ungefähr 1/20, 69 Dollar pro Tag. Es liegt ein Sicherheitsproblem vor, da das AWS-SDK nicht verwendet werden kann. Etwas mehr als das ...
Es ist wahrscheinlich Sorya.
** <Konfiguration D: SQS + signierte URL> **
Wenn Sie sorgfältig darüber nachdenken, können Sie es anscheinend gut machen, wenn Sie eine Authentifizierung ohne SDK durchführen und diese direkt an SQS senden können.
Um einen solchen Mechanismus zu erstellen, werden wir eine mit SQS + signierte URL realisieren.
** Die auszuführende Verarbeitung und der Ausführungszeitpunkt von jedem sind wie folgt **
wird bearbeitet | Ziel | zeitliche Koordinierung |
---|---|---|
SQS-signierte URL abrufen | Terminal → API-Gateway | Einmal alle 15 Minuten ausführen |
Terminalstatus an SQS senden | Terminal → SQS | Alle 5 Sekunden einmal ausführen |
** Die von SQS ausgelösten Daten werden diesmal wie folgt angenommen **
Zu sendende Daten | Dateninhalt |
---|---|
Name der SQS-Warteschlange | sqs-send-request-test-0424 |
Muster der zu übertragenden Daten | Open/Offen (Terminal an, menschliches Gefühl an) Close/Offen (Terminal aus, menschliches Gefühl an) Open/Schließen (Terminal ein, menschliches Gefühl aus) Close/Schließen (Terminal aus, menschliches Gefühl aus) * Senden Sie eine von 4 Möglichkeiten |
Fordern Sie eine signierte URL vom API-Gateway an [^ 1]
[^ 1]: * Die API-Gateway-Authentifizierung wird dieses Mal weggelassen. Wenn Sie sich authentifizieren möchten, geben Sie die Authentifizierungsinformationen in den Header der übertragenen Daten ein.
Terminalseitige Anfrage
curl "https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/url" -s -X POST \
-d '{"que_name":"sqs-send-request-test-0424", "patterns":["Open/Open","Close/Open","Open/Close","Close/Close"]}'
Wenn die Anforderung erfolgreich ist, erhalten Sie die gleiche Anzahl signierter URLs wie das Datenmuster.
Terminalseite empfangene Daten
{
"url": {
"Open/Open": "https://sqs.ap-northeast-1.amazonaws.com/xxxxxx/sqs-send-request-test-0424?AWSAccessKeyId=xxxxx&Action=SendMessage&MessageBody=Open%2FOpen&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2020-04-30T10%3A42%3A54&Version=2012-11-05&Signature=xxxxxxxxxxxxxxxxxxxxx",
"Close/Open": "https://sqs.ap-northeast-1.amazonaws.com/xxxxxx/sqs-send-request-test-0424?AWSAccessKeyId=xxxxx&Action=SendMessage&MessageBody=Close%2FOpen&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2020-04-30T10%3A42%3A54&Version=2012-11-05&Signature=xxxxxxxxxxxxxxxxxxxxx",
"Open/Close": "https://sqs.ap-northeast-1.amazonaws.com/xxxxxx/sqs-send-request-test-0424?AWSAccessKeyId=xxxxxx&Action=SendMessage&MessageBody=Open%2FClose&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2020-04-30T10%3A42%3A54&Version=2012-11-05&Signature=xxxxxxxxxxxxxxxxxxxxx",
"Close/Close": "https://sqs.ap-northeast-1.amazonaws.com/xxxxxx/sqs-send-request-test-0424?AWSAccessKeyId=xxxxxx&Action=SendMessage&MessageBody=Close%2FClose&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2020-04-30T10%3A42%3A54&Version=2012-11-05&Signature=xxxxxxxxxxxxxxxxxxxxx"
}
}
Die zu sendende URL sind die Daten der Daten ["url"] [$ {Status, den Sie senden möchten}]. Im Beispiel wird "Öffnen / Schließen" gesendet.
Terminalseitige Anfrage
curl "https://sqs.ap-northeast-1.amazonaws.com/xxxxxx/sqs-send-request-test-0424?AWSAccessKeyId=xxxxxx&Action=SendMessage&MessageBody=Open%2FClose&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2020-04-30T10%3A42%3A54&Version=2012-11-05&Signature=xxxxxxxxxxxxxxxxxxxxx"
Jedes Mal, wenn Sie es ausführen, wird eine $ {Status, den Sie senden möchten} -Nachricht im festgelegten Thema registriert. Im Beispiel ist "Öffnen / Schließen" in "sqs-send-request-test-0424" registriert.
Stellen Sie als vorläufige Vorbereitung eine Warteschlange bei SQS auf. Geben Sie den Namen der gewünschten Warteschlange ein und klicken Sie unten auf dem Bildschirm auf "Quick Create Queue".
Erstellen Sie außerdem einen IAM-Benutzer für SQS. Setzen Sie AmazonSQSFullAccess auf die Richtlinie. Es sind keine anderen Berechtigungen als SQS erforderlich.
Rufen Sie nach dem Erstellen des IAM-Benutzers die Zugriffsschlüssel-ID und den geheimen Zugriffsschlüssel ab.
Erstellen Sie Lambda mit Python 3.8.
Stellen Sie die Lambda-Umgebungsvariablen wie folgt ein.
Umgebungsvariablenschlüssel | Zu setzender Wert |
---|---|
AWS_ACCOUNT_NUMBER | AWS-Konto-ID-Nummer (Die 12-stellige Nummer unten links auf dem IAM-Bildschirm) |
SQS_ACCOUNT_ID | IAM-Benutzerzugriffsschlüssel-ID für SQS |
SQS_SECRET_KEY | Geheimer Zugriffsschlüssel für IAM-Benutzer, die SQS gewidmet sind |
Fügen Sie die folgende Quelle in Lambda ein.
Lambda
# coding: utf-8
import boto3, json, hashlib, hmac, base64, os
from datetime import datetime, timezone, timedelta
from urllib import parse as url_encode
#Signaturinformationen (SHA256-Format, Signaturversion ist 2)
SIGNATURE_METHOD = "HmacSHA256"
SIGNATURE_VERSION = "2"
ENCODE = "utf-8"
#Informationen zur SQS-Methode (Nachricht mit REST API GET an Queue senden)
HTTP_METHOD = "GET"
SQS_METHOD = "SendMessage"
AWS_VERSION = "2012-11-05"
#Zeitzone
UTC_TIMEZONE = timezone(timedelta(hours = 0), 'UTC')
class Credentials:
"""
Legen Sie die Anmeldeinformationen des IAM-Benutzers fest
"""
@staticmethod
def from_iam():
instance = Credentials()
instance.aws_access_key = os.environ.get("SQS_ACCOUNT_ID", DEFAULT.SQS_ACCOUNT_ID)
instance.aws_secret_key = os.environ.get("SQS_SECRET_KEY", DEFAULT.SQS_SECRET_KEY)
return instance
class Endpoint:
"""
Legen Sie die SQS-Endpunktinformationen fest
"""
def __init__(self, topic_name):
self.protocol = "https"
self.host_name = "sqs.{}.amazonaws.com".format(os.environ.get("AWS_REGION", DEFAULT.AWS_REGION))
self.url_path = "/{}/{}".format(os.environ.get("AWS_ACCOUNT_NUMBER", DEFAULT.AWS_ACCOUNT_NUMBER), topic_name)
@property
def url(self):
return f"{self.protocol}://{self.host_name}{self.url_path}"
#Erstellen Sie eine SQS-signierte URL
def create_presigned_url(credential, endpoint, message):
#Holen Sie sich das aktuelle Datum und die aktuelle Uhrzeit mit UTC und konvertieren Sie es in eine Zeichenfolge
current_date = datetime.now().astimezone(UTC_TIMEZONE)
current_date_str = url_encode.quote(
current_date.strftime('%Y-%m-%dT%H:%M:%S')
)
#Erstellen Sie einen Hash mit einem geheimen Zugriffsschlüssel basierend auf den zu sendenden Daten
return endpoint.url + "?" + create_query(SQS_METHOD, message, credential.aws_access_key, current_date_str, option = {
#Da die Hash-Daten ein Byte-Array sind, codieren Sie URL + base64, damit sie von GET gesendet werden können.
"Signature" : url_encode.quote(
base64.b64encode(
sign(
#Geben Sie den geheimen Zugriffsschlüssel an, der zum Signieren verwendet werden soll
credential.aws_secret_key.encode(ENCODE),
#Geben Sie die Übertragungsdaten an (die angegebenen Daten werden mit SHA256 gehasht).
create_certificate(endpoint, SQS_METHOD, message, credential.aws_access_key, current_date_str)
)
)
)
})
#Hash mit geheimem Zugangsschlüssel
def sign(key, msg):
return hmac.new(key, msg.encode(ENCODE), hashlib.sha256).digest()
#Erstellen Sie Signaturdaten im v2-Format
#Beziehen Sie sich auf das offizielle Dokument für das Format (https)://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-2.html)
def create_certificate(endpoint, method, message_body, aws_access_key, current_date_str):
return "\n".join([
HTTP_METHOD,
endpoint.host_name,
endpoint.url_path,
create_query(method, message_body, aws_access_key, current_date_str)
])
#Abfragedaten normalisieren
#Beziehen Sie sich auf das offizielle Dokument für das Format (https)://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-2.html)
def create_query(method, message_body, aws_access_key, current_date_str, option = None):
query_map = {
"AWSAccessKeyId" : aws_access_key,
"Action" : method,
"MessageBody" : message_body,
"SignatureMethod" : SIGNATURE_METHOD,
"SignatureVersion" : SIGNATURE_VERSION,
"Timestamp" : current_date_str,
"Version" : AWS_VERSION
}
#Die Signatur sollte nur beim Senden nicht in den Hash aufgenommen werden
#Fügen Sie der Abfrage Daten hinzu, wenn Signatur angegeben ist
if option is not None:
query_map.update(option)
#In das GET-Abfrageformat konvertieren
return "&".join([
f"{key}={value}"
for key, value in query_map.items()
])
#Erstellen Sie so viele signierte URLs, wie Sie benötigen
def request(credential, endpoint, data_patterns):
url = {}
for pattern in data_patterns:
url[pattern] = create_presigned_url(credential, endpoint, url_encode.quote(pattern, safe = ""))
return {
"url" : url
}
#POST-Daten von APIGateway-Argumenten (HTTP-API) abrufen (Daten sind auf der APIGateway-Seite base64-codiert)
def get_payload_from_event(event):
payload_str = ""
if event["isBase64Encoded"]:
payload_str = base64.b64decode(event["body"].encode(ENCODE))
else:
payload_str = event["body"]
return json.loads(payload_str)
#Einstiegspunkt beim Ausführen von Lambda
def lambda_handler(event, context):
payload = get_payload_from_event(event)
return {
'statusCode': 200,
'body': json.dumps(request(Credentials.from_iam(), Endpoint(payload["que_name"]), payload["patterns"]))
}
# ---------------------------------------------
#Das Folgende ist für die lokale Ausführung
#Geben Sie an, wenn Sie mit einem anderen als Lambda arbeiten
# ---------------------------------------------
#Variablen für die lokale Ausführung
class _Default:
def __init__(self):
self.SQS_ACCOUNT_ID = "" #Geben Sie die IAM-Zugriffsschlüssel-ID an
self.SQS_SECRET_KEY = "" #Geben Sie den geheimen IAM-Schlüssel an
self.AWS_ACCOUNT_NUMBER = "" #Geben Sie die AWS-Konto-ID an
self.AWS_REGION = "ap-northeast-1" #Geben Sie die Region an, in der sich SQS befindet
self.SQS_QUEUE_NAME = "" #Geben Sie den Namen der Zielwarteschlange an
DEFAULT = _Default()
#Einstiegspunkt beim Ausführen des Debugings in der lokalen Umgebung
if __name__ == "__main__":
print(json.dumps(request(Credentials.from_iam(), Endpoint(DEFAULT.SQS_QUEUE_NAME), [
"Open/Open", "Close/Open", "Wait/Open",
"Open/Close", "Close/Close", "Wait/Close",
"Open/Wait", "Close/Wait", "Wait/Wait"
])))
Legen Sie das erstellte Lambda als Back-End des API-Gateways fest.
Wenn es in Ordnung ist, wenn Sie sich bewegen, ist es in Ordnung, wenn Sie so weit lesen. Nach der Bereitstellung von API Gateway sollte es genau wie die "fertige Zeichnung" funktionieren.
Von hier an wird es eine detaillierte Geschichte sein.
Ursprünglich verfügt SQS über einen Mechanismus zum Senden von Nachrichten per GET oder POST, ohne das AWS-SDK zu durchlaufen.
Referenz: Stellen Sie eine Abfrage-API-Anfrage https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-making-api-requests.html
Die einfachste Anforderungsmethode ist wie folgt. Wenn Sie auf der Referenzsite auf die URL klicken, wird eine Nachricht (Daten) an die Warteschlange (MyQueue) gesendet. [^ 2]
[^ 2]: * Version ist die Version von SQS. Vorerst können Sie es senden, ohne an irgendetwas zu denken.
https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue ?
Version = 2012-11-05 &
Action = SendMessage &
MessageBody = data
Beachten Sie, dass diese Abfrage Nachrichten von anonymen Benutzern sendet. Die Standardwarteschlange kommt nicht mit einem Berechtigungsfehler an.
Um Nachrichten in diesem Status zu empfangen, müssen Sie sie so eingestellt haben, dass sie die öffentliche Offenlegung akzeptieren. Ändern Sie die Warteschlangenberechtigungen als erfasst und aktivieren Sie "Jeder".
Wenn Sie an einen bestimmten Benutzer senden möchten, ohne die öffentliche Version zu akzeptieren, setzen Sie "Wer bin ich".
https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue ?
Version = 2012-11-05 &
Action = SendMessage &
MessageBody = data &
AWSAccessKeyId = AKIA****************
Da ich die AWSAccessKeyID festgelegt habe, kann "jemand" kommuniziert werden. Ich weiß jedoch nicht, ob dies wirklich die Person ist. Sie können sich nur als Sie selbst ausgeben.
Verwenden Sie den geheimen Zugangsschlüssel, um Ihre Identität zu beweisen. Da es jedoch nicht möglich ist, den geheimen Zugriffsschlüssel so wie er ist zu senden, senden wir die Hash-Version.
https://sqs.us-east-2.amazonaws.com/123456789012/MyQueue ?
Version = 2012-11-05 &
Action = SendMessage &
MessageBody = data &
AWSAccessKeyId = AKIA**************** &
Signature = ********************************** &
SignatureMethod = HmacSHA256 &
SignatureVersion = 2 &
Timestamp = 2020-04-30T10:42:54
Die Signatur ist ein Hash der zu sendenden Daten, wobei der geheime Zugriffsschlüssel als Schlüssel verwendet wird. Die zu sendenden Daten sind die gesamte Abfrage ohne Signatur und die Hostinformationen zusammen.
Die Signaturmethode ist der Algorithmus, mit dem die Signatur gehasht wird. Da es sich um HMAC-SHA256 handelt, werde ich AWS davon erzählen.
Signaturversion ist die Signaturversion. Dieses Mal verwende ich Signatur Version 2.
TimeStamp ist das Datum und die Uhrzeit des Hashings.
Referenz: Signieren des Signaturprozesses für Version 2 https://docs.aws.amazon.com/ja_jp/general/latest/gr/signature-version-2.html
Das Verhalten unterscheidet sich von der "signierten URL" des ursprünglichen S3.
** Der Bereich, in dem Daten nach der Ausgabe der URL geändert werden können, ist unterschiedlich **
In SQS ändert sich die Signatur abhängig vom Inhalt der gesendeten Nachricht. Mit S3 können Sie unabhängig vom Inhalt der von Ihnen gesendeten Datei mit derselben Signatur senden.
Um verschiedene Nachrichten mit SQS zu senden, müssen Sie so viele Signaturen ausstellen.
** Die Lebensdauer der von STS übergebenen temporären Anmeldeinformationen ist unterschiedlich **
Für S3 ist die von Lambda ausgegebene temporäre Zugriffsschlüssel-ID verfügbar, bis die signierte URL abläuft. Was passiert, wenn Sie eine temporäre Zugriffsschlüssel-ID und einen geheimen Zugriffsschlüssel auch in SQS ausstellen und gewähren?
Da die Zugriffsschlüssel-ID beim Beenden von Lambda verschwindet, wird die Authentifizierung nicht bestanden, wenn Lambda die URL an API Gateway zurückgibt.
Recommended Posts