AWS API Usage in Elisp
Here's some sample elisp code for signing Amazon Web Services (AWS) API requests. The value (first element) returned by (aws-sign4) is used in Authorization header while making a request. When the function is called with an expires value, it returns a URL which can be directly used in a browser.
(require 'aws-sign4)
(let ((*aws-credentials*
(lambda ()
(values "AKIAIOSFODNN7EXAMPLE" "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"))))
(aws-sign4 :region "eu-west-1"
:service "s3"
:host "s3-eu-west-1.amazonaws.com"
:path "/some-bucket/some-file"
))
(lambda ()
(values "AKIAIOSFODNN7EXAMPLE" "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"))))
(aws-sign4 :region "eu-west-1"
:service "s3"
:host "s3-eu-west-1.amazonaws.com"
:path "/some-bucket/some-file"
))
(let ((*aws-credentials*
(lambda ()
(values "AKIAIOSFODNN7EXAMPLE" "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"))))
(aws-sign4 :region "us-east-1"
:service "iam"
:host "iam.amazonaws.com"
:params '(("Action" . "CreateUser")
("UserName" . "NewUser")
("Version" . "2010-05-08"))
:expires 30))
(lambda ()
(values "AKIAIOSFODNN7EXAMPLE" "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"))))
(aws-sign4 :region "us-east-1"
:service "iam"
:host "iam.amazonaws.com"
:params '(("Action" . "CreateUser")
("UserName" . "NewUser")
("Version" . "2010-05-08"))
:expires 30))
;; Convenience function
;; aws-url-retrieve (url &optional auth-header region payload headers service method)
;; Simple GET URL (default region: "us-east-1")
(aws-url-retrieve "https://iam.amazonaws.com?Action=CreateUser&UserName=NewUser&Version=2010-05-08")
(aws-url-retrieve "https://iam.amazonaws.com?Action=CreateUser&UserName=NewUser&Version=2010-05-08")
;; GET URL with authentication header
(aws-url-retrieve "https://s3.amazonaws.com/" t nil nil `(,(cons "x-amz-content-sha256" (hash ""))))
(aws-url-retrieve "https://s3.amazonaws.com/" t nil nil `(,(cons "x-amz-content-sha256" (hash ""))))
;; DELETE s3 bucket test-axe in region us-east-1
(aws-url-retrieve "https://test-axe.s3.us-east-1.amazonaws.com/" t nil nil
`(,(cons "x-amz-content-sha256" (hash "")))
"s3"
"DELETE")
`(,(cons "x-amz-content-sha256" (hash "")))
"s3"
"DELETE")
;; POST URL - DynamoDB create table
(aws-url-retrieve "https://dynamodb.us-west-2.amazonaws.com/" t "us-west-2"
(concat
"{\"KeySchema\": [{\"KeyType\": \"HASH\",\"AttributeName\": \"Id\"}],"
"\"TableName\": \"TestTable\",\"AttributeDefinitions\": [{\"AttributeName\": \"Id\",\"AttributeType\": \"S\"}],"
"\"ProvisionedThroughput\": {\"WriteCapacityUnits\": 5,\"ReadCapacityUnits\": 5}}")
`(,(cons "content-type" "application/x-amz-json-1.0")
,(cons "x-amz-target" "DynamoDB_20120810.CreateTable")
))
(aws-url-retrieve "https://dynamodb.us-west-2.amazonaws.com/" t "us-west-2"
(concat
"{\"KeySchema\": [{\"KeyType\": \"HASH\",\"AttributeName\": \"Id\"}],"
"\"TableName\": \"TestTable\",\"AttributeDefinitions\": [{\"AttributeName\": \"Id\",\"AttributeType\": \"S\"}],"
"\"ProvisionedThroughput\": {\"WriteCapacityUnits\": 5,\"ReadCapacityUnits\": 5}}")
`(,(cons "content-type" "application/x-amz-json-1.0")
,(cons "x-amz-target" "DynamoDB_20120810.CreateTable")
))
;; POST URL - DynamoDB delete table
(aws-url-retrieve "https://dynamodb.us-west-2.amazonaws.com/" t "us-west-2"
(concat
"{\"TableName\": \"TestTable\"}")
`(,(cons "content-type" "application/x-amz-json-1.0")
,(cons "x-amz-target" "DynamoDB_20120810.DeleteTable")
))
(concat
"{\"TableName\": \"TestTable\"}")
`(,(cons "content-type" "application/x-amz-json-1.0")
,(cons "x-amz-target" "DynamoDB_20120810.DeleteTable")
))
Code
Key points
- Requests are signed using a timestamp e.g. "20221018T072146Z". A timestamp older than 5 minutes is considered invalid. For testing, you might want to use a hard-coded timestamp using :request-date.
- Each AWS service might need a different set of mandatory headers. Look up the documentation for the same.
List S3 buckets using AXE |
References
- Request signing https://github.com/rotatef/aws-sign4
- AWS usage tools - AXE https://github.com/cniles/axe
- https://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
- AWS S3 with Tramp (cloud storage in general) via rclone https://www.gnu.org/software/tramp/#rclone-setup
Comments
Post a Comment