Created
April 15, 2020 15:47
-
-
Save rezan/18d86a70cac248a855bbec5480565a65 to your computer and use it in GitHub Desktop.
AWS Secrets Manager Varnish VCL Implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# AWS Secrets Manager v1.0 | |
# | |
import crypto; | |
import http; | |
import json; | |
import kvstore; | |
import utils; | |
sub vcl_init | |
{ | |
# Init the secret storage | |
new aws_secret = kvstore.init(); | |
} | |
sub aws_get_secret | |
{ | |
# | |
# aws_secret kvstore must be initialized: | |
# | |
# aws_secret.init_conf("/etc/varnish/aws_secret.conf"); | |
# | |
# OR: | |
# | |
# aws_secret.set("access-key", "AKAI..."); | |
# aws_secret.set("secret-key", "..."); | |
# aws_secret.set("region", "us-west-2"); | |
# aws_secret.set("secret-id", "mykey"); | |
# aws_secret.set("version-stage", "AWSPREVIOUS"); //optional, default AWSCURRENT | |
# | |
# Response: | |
# | |
# aws_secret.get("secret"); | |
# aws_secret.get("response-status"); | |
# aws_secret.get("response-code"); | |
# aws_secret.get("response-body"); | |
# | |
# Setup | |
aws_secret.delete("secret"); | |
aws_secret.delete("response-status"); | |
aws_secret.delete("response-code"); | |
aws_secret.delete("response-body"); | |
# Incorrect configuration error | |
if (!aws_secret.get("access-key") || !aws_secret.get("secret-key") || | |
!aws_secret.get("region") || !aws_secret.get("secret-id")) { | |
return (fail("Configuration not found. Required: access-key, secret-key, region, secret-id")); | |
} | |
# More setup | |
aws_secret.set("_payload", {" | |
{ | |
"SecretId": "} + json.stringify(aws_secret.get("secret-id")) + {", | |
"VersionStage": "} + json.stringify(aws_secret.get("version-stage", "AWSCURRENT")) + {" | |
} | |
"}); | |
# Prepare the AWS secretsmanager v4 signed request | |
http.init(0, LOW); | |
http.req_set_method(0, "POST"); | |
http.req_set_url(0, "https://secretsmanager." + aws_secret.get("region") + ".amazonaws.com/"); | |
http.req_set_sparam(0, "POSTFIELDS", aws_secret.get("_payload")); | |
http.req_set_header(0, "Content-Type", "application/x-amz-json-1.1"); | |
http.req_set_header(0, "Host", "secretsmanager." + aws_secret.get("region") + ".amazonaws.com"); | |
http.req_set_header(0, "x-amz-target", "secretsmanager.GetSecretValue"); | |
http.req_set_header(0, "x-amz-date", utils.time_format("%Y%m%dT%H%M%SZ")); | |
http.req_set_header(0, "s3-datestamp", utils.time_format("%Y%m%d")); | |
http.req_set_header(0, "s3-signed-headers", "host;x-amz-content-sha256;x-amz-date;x-amz-target"); | |
http.req_set_header(0, "s3-scope", http.req_get_header(0, "s3-datestamp") + "/" + | |
aws_secret.get("region") + "/secretsmanager/aws4_request"); | |
http.req_set_header(0, "x-amz-content-sha256", | |
crypto.hex_encode(crypto.hash(sha256, aws_secret.get("_payload")))); | |
http.req_set_header(0, "s3-canonical-request", | |
crypto.hex_encode(crypto.hash(sha256, | |
"POST" + utils.newline() + | |
"/" + utils.newline() + | |
"" + utils.newline() + | |
"host:" + http.req_get_header(0, "Host") + utils.newline() + | |
"x-amz-content-sha256:" + http.req_get_header(0, "x-amz-content-sha256") + utils.newline() + | |
"x-amz-date:" + http.req_get_header(0, "x-amz-date") + utils.newline() + | |
"x-amz-target:" + http.req_get_header(0, "x-amz-target") + utils.newline() + | |
utils.newline() + | |
http.req_get_header(0, "s3-signed-headers") + utils.newline() + | |
http.req_get_header(0, "x-amz-content-sha256")) | |
)); | |
http.req_set_header(0, "s3-signature", | |
crypto.hex_encode(crypto.hmac(sha256, | |
crypto.hmac(sha256, | |
crypto.hmac(sha256, | |
crypto.hmac(sha256, | |
crypto.hmac(sha256, | |
crypto.blob("AWS4" + aws_secret.get("secret-key")), | |
http.req_get_header(0, "s3-datestamp")), | |
aws_secret.get("region")), | |
"secretsmanager"), | |
"aws4_request"), | |
"AWS4-HMAC-SHA256" + utils.newline() + | |
http.req_get_header(0, "x-amz-date") + utils.newline() + | |
http.req_get_header(0, "s3-scope") + utils.newline() + | |
http.req_get_header(0, "s3-canonical-request")) | |
)); | |
http.req_set_header(0, "Authorization", | |
"AWS4-HMAC-SHA256 " + | |
"Credential=" + aws_secret.get("access-key") + "/" + | |
http.req_get_header(0, "s3-scope") + ", " + | |
"SignedHeaders=" + http.req_get_header(0, "s3-signed-headers") + ", " + | |
"Signature=" + http.req_get_header(0, "s3-signature")); | |
http.req_unset_header(0, "s3-prefix"); | |
http.req_unset_header(0, "s3-datestamp"); | |
http.req_unset_header(0, "s3-signed-headers"); | |
http.req_unset_header(0, "s3-scope"); | |
http.req_unset_header(0, "s3-canonical-request"); | |
http.req_unset_header(0, "s3-signature"); | |
# Send the request | |
http.req_send(0); | |
http.resp_wait(0); | |
# Set the response fields | |
aws_secret.set("response-status", http.resp_get_status(0)); | |
aws_secret.set("response-code", http.resp_get_errorcode(0)); | |
aws_secret.set("response-body", http.resp_get_body(0)); | |
# Find the SecretString in the payload | |
if (http.resp_get_status(0) == 200) { | |
json.parse(http.resp_get_body(0)); | |
if (json.is_object() && json.get("SecretString")) { | |
aws_secret.set("secret", json.get("SecretString")); | |
} | |
} | |
# Done | |
http.finish(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment