Created
April 29, 2011 14:57
-
-
Save justincormack/948423 to your computer and use it in GitHub Desktop.
Using Lua and Nginx to proxy Amazon web services example
This file contains 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
# example location parts of nginx.conf | |
# add your own AWS keys, server lines etc, and set your aws domains, paths | |
http { | |
# you will need the luacrypto in the cpath, download from http://luacrypto.luaforge.net/ | |
lua_package_cpath "/home/justin/lua/luacrypto-0.2.0/src/l?.so.0.2.0;;"; | |
server { | |
listen 80; | |
location ~ "^/sdb.*$" { | |
set $aws_access_key "%AWS_ACCESS_KEY%"; | |
set $aws_secret_key "%AWS_SECRET_KEY%"; | |
set $domain "index.node3.org"; | |
set_by_lua_file $query "..path to../sdb.lua"; | |
rewrite .* /?$query break; | |
proxy_pass http://sdb.amazonaws.com; | |
} | |
location ~ "^/s3/(.*)$" { | |
set $aws_access_key "%AWS_ACCESS_KEY%"; | |
set $aws_secret_key "%AWS_SECRET_KEY%"; | |
set $bucket "repo.node3.org"; | |
set $key $1; | |
set_by_lua $now "return ngx.cookie_time(ngx.time())"; | |
set $string_to_sign "$request_method\n$http_content_md5\n$http_content_type\n\nx-amz-date:$now\n/$bucket/$key"; | |
set_by_lua $aws_signature " | |
local crypto = require 'crypto' | |
digest = crypto.hmac.digest('sha1', ngx.var.string_to_sign, ngx.var.aws_secret_key, true) | |
return ngx.encode_base64(digest) | |
"; | |
proxy_set_header x-amz-date $now; | |
proxy_set_header Authorization "AWS $aws_access_key:$aws_signature"; | |
rewrite .* /$key break; | |
proxy_set_header Host $bucket.s3.amazonaws.com; | |
proxy_pass http://s3.amazonaws.com; | |
} | |
} | |
} |
This file contains 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
local crypto = require 'crypto' | |
a = ngx.var.args | |
ts = {} | |
ks = {} | |
es = {} | |
function kv(s) | |
local l | |
if #s == 0 then return end | |
l = string.find(s, '=', 1, true) | |
if l == nil then | |
return s, '' | |
else | |
return string.sub(s, 1, l - 1), string.sub(s, l + 1) | |
end | |
end | |
-- unreserved characters are unchanged, others % encoded. | |
-- http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/index.html?Query_QueryAuth.html | |
-- A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), and tilde ( ~ ). | |
-- note we do not re-urlencode inbound data, as nginx does not decode, so this should be encoded using these same rules to pass signature | |
function psub(c) | |
return '%' .. string.format('%2X', string.byte(c, 1)) | |
end | |
function urlencode(s) | |
return string.gsub(s, '[^a-zA-Z0-9%-_%.~]', psub) | |
end | |
function extra(k, v) | |
local uv = urlencode(v) | |
es[k] = uv | |
if ts[k] == nil then | |
ts[k] = uv | |
table.insert(ks, k) | |
end | |
end | |
local utc = ngx.utctime() | |
local now = string.sub(utc, 1, 10) .. 'T' .. string.sub(utc, 12) .. 'Z' | |
ll = 0 | |
local l, s, k, v | |
while true do | |
l = string.find(a, '&', ll, true) | |
if l ~= nil then | |
s = string.sub(a, ll, l - 1) | |
else | |
s = string.sub(a, ll) | |
end | |
k, v = kv(s) | |
if k then | |
ts[k] = v | |
table.insert(ks, k) | |
end | |
if l == nil then break end | |
ll = l + 1 | |
end | |
extra('Timestamp', now) | |
extra('Version', '2009-04-15') | |
extra('SignatureMethod', 'HmacSHA256') | |
extra('SignatureVersion', '2') | |
extra('AWSAccessKeyId', ngx.var.aws_access_key) | |
extra('DomainName', ngx.var.domain) | |
table.sort(ks) | |
for k, v in pairs(ks) do | |
ks[k] = v .. '=' .. ts[v] | |
end | |
string_to_sign = 'GET\nsdb.amazonaws.com\n/\n' .. table.concat(ks, '&') | |
signature = ngx.encode_base64(crypto.hmac.digest('sha256', string_to_sign, ngx.var.aws_secret_key, true)) | |
-- note we return additional query string, as nginx rewrite leaves original parameters | |
ee = {} | |
for k, v in pairs(es) do | |
table.insert(ee, k .. '=' .. v) | |
end | |
query = table.concat(ee, '&') .. '&Signature=' .. urlencode(signature) | |
return query |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment