67
Roll Your Own API Management Platform with nginx and Lua Jon Moore Senior Fellow, Comcast Cable @jon_moore

Roll Your Own API Management Platform with nginx and Lua

Embed Size (px)

Citation preview

Page 1: Roll Your Own API Management Platform with nginx and Lua

Roll Your Own API Management Platform with nginx and Lua Jon Moore Senior Fellow, Comcast Cable @jon_moore

Page 2: Roll Your Own API Management Platform with nginx and Lua

access control

Page 3: Roll Your Own API Management Platform with nginx and Lua

capacity management (“rate limiting”)

Page 4: Roll Your Own API Management Platform with nginx and Lua

capacity management (“rate limiting”)

Page 5: Roll Your Own API Management Platform with nginx and Lua

HTTP

Proxy

custom logic!

Page 6: Roll Your Own API Management Platform with nginx and Lua

Lua

Page 7: Roll Your Own API Management Platform with nginx and Lua
Page 8: Roll Your Own API Management Platform with nginx and Lua
Page 9: Roll Your Own API Management Platform with nginx and Lua

--- Validates the OAuth signature!-- @return Const.HTTP_UNAUTHORIZED if either the key or signature is invalid!-- this method is internal and should not be called directly!function _M.validate_signature(self)! local headers = self.req.get_oauth_params()! local key = headers[Const.OAUTH_CONSUMER_KEY]! local keyconf = self.conf.keys[key]! if keyconf == nil then! return {! code = Const.HTTP_UNAUTHORIZED! error = Const.ERROR_INVALID_CONSUMER_KEY! }! end!! local sig = get_hmac_signature(self.req, keyconf.secret)! if sig ~= headers[Const.OAUTH_SIGNATURE] then! return {! code = Const.HTTP_UNAUTHORIZED,! error = Const.ERROR_INVALID_SIGNATURE! }! end!end!

Page 10: Roll Your Own API Management Platform with nginx and Lua

Lua < 3k LOC

Page 11: Roll Your Own API Management Platform with nginx and Lua

testing

Page 12: Roll Your Own API Management Platform with nginx and Lua

function TestOAuth1:test_reject_request_when_signature_invalid()! local header = Header:new()! header[Const.OAUTH_SIGNATURE] = “invalid”! local req = Req:new({oauth_params = header })! local conf = Conf:new()! local oauth = OAuth1:new(conf, req)!! local res = oauth:authorize()! assertEquals(res.code, Const.HTTP_UNAUTHORIZED)! assertEquals(res.error, Const.ERROR_INVALID_SIGNATURE)!end!!lu = LuaUnit.new()!Lu:setOutputType(“tap”)!os.exit(lu:runSuite())!

Page 13: Roll Your Own API Management Platform with nginx and Lua

ngx.log(ngx.ERR, “oops”)!

Page 14: Roll Your Own API Management Platform with nginx and Lua

ngx.log(ngx.ERR, “oops”)!

Page 15: Roll Your Own API Management Platform with nginx and Lua

function get_oauth_params_from_auth_header()!

Page 16: Roll Your Own API Management Platform with nginx and Lua

function get_oauth_params_from_auth_header(env)! env = env or ngx! local auth_hdrs = env.req.get_headers()[“Authorization”]! ...!

Page 17: Roll Your Own API Management Platform with nginx and Lua

function get_oauth_params_from_auth_header(env)! env = env or ngx! local auth_hdrs = env.req.get_headers()[“Authorization”]! ...!

Page 18: Roll Your Own API Management Platform with nginx and Lua

function get_oauth_params_from_auth_header(env)! env = env or ngx! local auth_hdrs = env.req.get_headers()[“Authorization”]! ...!

Page 19: Roll Your Own API Management Platform with nginx and Lua

function TestRequest:test_retrieve_oauth_params_from_header()! local header = [[Oauth realm=“example.com”, ]]! .. [[oauth_consumer_key=“mykey”,]]! .. [[oauth_version=“1.0”]]! local ngx = StubNgx:new({ Authorization = header })! local res = get_oauth_params_from_auth_header(ngx)! assertEquals(“1.0”, res.oauth_version)! ...!

Page 20: Roll Your Own API Management Platform with nginx and Lua

function TestRequest:test_retrieve_oauth_params_from_header()! local header = [[Oauth realm=“example.com”, ]]! .. [[oauth_consumer_key=“mykey”,]]! .. [[oauth_version=“1.0”]]! local ngx = StubNgx:new({ Authorization = header })! local res = get_oauth_params_from_auth_header(ngx)! assertEquals(“1.0”, res.oauth_version)! ...!

Page 21: Roll Your Own API Management Platform with nginx and Lua

function TestRequest:test_retrieve_oauth_params_from_header()! local header = [[Oauth realm=“example.com”, ]]! .. [[oauth_consumer_key=“mykey”,]]! .. [[oauth_version=“1.0”]]! local ngx = StubNgx:new({ Authorization = header })! local res = get_oauth_params_from_auth_header(ngx)! assertEquals(“1.0”, res.oauth_version)! ...!

Page 22: Roll Your Own API Management Platform with nginx and Lua

function TestRequest:test_retrieve_oauth_params_from_header()! local header = [[Oauth realm=“example.com”, ]]! .. [[oauth_consumer_key=“mykey”,]]! .. [[oauth_version=“1.0”]]! local ngx = StubNgx:new({ Authorization = header })! local res = get_oauth_params_from_auth_header(ngx)! assertEquals(“1.0”, res.oauth_version)! ...!

Page 23: Roll Your Own API Management Platform with nginx and Lua

function TestRequest:test_retrieve_oauth_params_from_header()! local header = [[Oauth realm=“example.com”, ]]! .. [[oauth_consumer_key=“mykey”,]]! .. [[oauth_version=“1.0”]]! local ngx = StubNgx:new({ Authorization = header })! local res = get_oauth_params_from_auth_header(ngx)! assertEquals(“1.0”, res.oauth_version)! ...!

Page 24: Roll Your Own API Management Platform with nginx and Lua
Page 25: Roll Your Own API Management Platform with nginx and Lua
Page 26: Roll Your Own API Management Platform with nginx and Lua

test harness

Page 27: Roll Your Own API Management Platform with nginx and Lua

nginx-oauth1.conf!

test harness

Page 28: Roll Your Own API Management Platform with nginx and Lua

nginx-oauth1.conf!

test harness

Page 29: Roll Your Own API Management Platform with nginx and Lua

nginx-oauth1.conf!

test harness

Page 30: Roll Your Own API Management Platform with nginx and Lua

nginx-oauth1.conf!

test harness

Page 31: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 32: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 33: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 34: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 35: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 36: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 37: Roll Your Own API Management Platform with nginx and Lua

def spec_using_valid_oauth_credentials(self, harness)! auth = OAuth1(“mykey”, “mysecret”)! body_data = “{‘function’: ‘tick’}”! harness.reset_data()! response = requests.post(root_url, data=body_data, auth=auth,! headers={‘Content-Type’:! ‘application/json’})! assert response.status_code == 200! assert “Authorization” in harness.forwarded_headers! assert “Oauth” in harness.forwarded_headers[“Authorization”]! assert harness.forwarded_body == body_data!

Page 38: Roll Your Own API Management Platform with nginx and Lua

capacity management

Page 39: Roll Your Own API Management Platform with nginx and Lua

N = XR # concurrent

requests

transaction rate

response time

Page 40: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

Page 41: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

N = XR = 2 req/s × 1s = 2 req

Page 42: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

N = XR = 2 req/s × 1s = 2 req

Page 43: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

N = XR = 2 req/s × 1s = 2 req

Page 44: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

N = XR = 2 req/s × 1s = 2 req

Page 45: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

N = XR = 2 req/s × 1s = 2 req

Page 46: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

1s 2 req/s

Page 47: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

N = XR = 2 req/s × 10s = 20 req

Page 48: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

N = XR = 2 req/s × 10s = 20 req

Page 49: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

N = XR = 2 req/s × 10s = 20 req

Page 50: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

N = XR = 2 req/s × 10s = 20 req

Page 51: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

N = XR = 2 req/s × 10s = 20 req

Page 52: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

N = XR = 2 req/s × 10s = 20 req

Page 53: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

✗ N = XR = 2 req/s × 10s = 20 req

Page 54: Roll Your Own API Management Platform with nginx and Lua

API Mgmt client origin

10s 2 req/s

✗ ✗ N = XR = 2 req/s × 10s = 20 req

Page 55: Roll Your Own API Management Platform with nginx and Lua

access_by_lua ...!

log_by_lua ...!

+1

-1

Page 56: Roll Your Own API Management Platform with nginx and Lua

deployment

Page 57: Roll Your Own API Management Platform with nginx and Lua
Page 58: Roll Your Own API Management Platform with nginx and Lua

Version Control

templates vault (keys)

nginx.conf!ssh!

Page 59: Roll Your Own API Management Platform with nginx and Lua

architecture

Page 60: Roll Your Own API Management Platform with nginx and Lua

HAProxy HAProxy

VIP

. . .

<API>

Page 61: Roll Your Own API Management Platform with nginx and Lua

DC1 DC2 DC3

VIP VIP VIP

entry-vip-dc1. A 10.1.0.1!

<foo> <foo> <bar>

<bar>

foo-dc1. CNAME entry-vip-dc1.!

foo. CNAME foo-dc1.! (GSLB)

entry-vip-dc2. A 10.2.0.1!entry-vip-dc3. A 10.3.0.1!

Page 62: Roll Your Own API Management Platform with nginx and Lua

DC1 DC2 DC3

VIP VIP VIP

entry-vip-dc1. A 10.1.0.1!

<foo> <foo> <bar>

<bar>

foo-dc1. CNAME entry-vip-dc1.!

foo. CNAME foo-dc1.! (GSLB)

entry-vip-dc2. A 10.2.0.1!entry-vip-dc3. A 10.3.0.1!

Page 63: Roll Your Own API Management Platform with nginx and Lua

DC1 DC2 DC3

VIP VIP VIP

entry-vip-dc1. A 10.1.0.1!

<foo> <foo> <bar>

<bar>

foo-dc1. CNAME entry-vip-dc1.!

foo. CNAME foo-dc1.! (GSLB)

entry-vip-dc2. A 10.2.0.1!entry-vip-dc3. A 10.3.0.1!

Page 64: Roll Your Own API Management Platform with nginx and Lua

DC1 DC2 DC3

VIP VIP VIP

entry-vip-dc1. A 10.1.0.1!

<foo> <foo> <bar>

<bar>

foo-dc1. CNAME entry-vip-dc1.!

foo. CNAME foo-dc1.! (GSLB)

entry-vip-dc2. A 10.2.0.1!entry-vip-dc3. A 10.3.0.1!

Page 65: Roll Your Own API Management Platform with nginx and Lua

DC1 DC2 DC3

VIP VIP VIP

entry-vip-dc1. A 10.1.0.1!

<foo> <foo> <bar>

<bar>

foo-dc1. CNAME entry-vip-dc1.!

foo. CNAME foo-dc1.! (GSLB)

entry-vip-dc2. A 10.2.0.1!entry-vip-dc3. A 10.3.0.1!

Page 66: Roll Your Own API Management Platform with nginx and Lua

DC1 DC2 DC3

VIP VIP VIP

entry-vip-dc1. A 10.1.0.1!

<foo> <foo> <bar>

<bar>

foo-dc1. CNAME entry-vip-dc1.!

foo. CNAME foo-dc1.! (GSLB)

entry-vip-dc2. A 10.2.0.1!entry-vip-dc3. A 10.3.0.1!

Page 67: Roll Your Own API Management Platform with nginx and Lua

Roll Your Own API Management with nginx and Lua

• nginx + Lua => great for HTTP middleware with a small amount of custom logic

• Automated test and deployment pipeline with Vagrant, Python, and Ansible

• Concurrent request limiting, not rate limiting • Network architecture with operational flexibility

Presentation title (optional) 67