Skip to content

Commit

Permalink
Merge branch 'futurice'
Browse files Browse the repository at this point in the history
  • Loading branch information
tomlarkworthy committed Jun 1, 2020
2 parents 1166a86 + 981d263 commit 07a4b3a
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 60 deletions.
1 change: 1 addition & 0 deletions google_cloud/openresty-beyondcorp/Dockerfile.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ RUN opm get jkeys089/lua-resty-hmac

ADD default.conf /etc/nginx/conf.d/default.conf
ADD login /assets/login
ADD swiss/ /usr/local/openresty/lualib/swiss/


16 changes: 13 additions & 3 deletions google_cloud/openresty-beyondcorp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,20 @@ The use of bash to start the script gives it an easier name to find to kill

killall "bash"

# Get prod tokens

https://openresty-flxotk3pnq-ew.a.run.app/login?token=true

# Test WAL verification

curl -X POST -d "{}" http://localhost:8080/wal-playback/
curl -X POST -d "{}" http://localhost:8080/wal-playback/

# Test token validation
curl http://localhost:8080/httptokeninfo?id_token=foo
curl http://localhost:8080/httptokeninfo?access_token=foo

curl http://localhost:8080/httptokeninfo?id_token=foo
curl http://localhost:8080/httptokeninfo?access_token=foo


# Test slack

curl http://localhost:8080/slack/command
3 changes: 2 additions & 1 deletion google_cloud/openresty-beyondcorp/build.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module "docker-mirror" {

# Hydrate docker template file into .build directory
resource "local_file" "dockerfile" {
depends_on = [template_dir.swiss]
content = templatefile("${path.module}/Dockerfile.template", {
project = local.project
image = local.base_image_name
Expand All @@ -23,7 +24,7 @@ resource "null_resource" "openresty_image" {
# Rebuild if we change the base image, dockerfile, or bpm-platform config
image = "eu.gcr.io/${local.project}/openresty:${local.base_image_tag}_${
sha1(
"${sha1(local_file.dockerfile.content)}${sha1(local_file.config.content)}${sha1(local_file.login.content)}"
"${sha1(local_file.dockerfile.content)}${sha1(local_file.config.content)}${sha1(local_file.login.content)}${data.archive_file.swiss.output_sha}"
)
}"
}
Expand Down
134 changes: 86 additions & 48 deletions google_cloud/openresty-beyondcorp/files/default.template.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
error_log /dev/stderr debug;
proxy_cache_path /tmp/cache keys_zone=tokens:10m;

init_by_lua_block {
require "cjson"
require "swiss.secretmanager"
require "swiss.slack"
require "resty.http"
require("ngx.base64")
}

server {
listen 8080;
Expand Down Expand Up @@ -185,61 +192,29 @@ server {

location /slack/command/ {
# https://api.slack.com/interactivity/slash-commands#app_command_handling
rewrite_by_lua_block {
local cjson = require "cjson"
rewrite_by_lua_block {
ngx.req.read_body()
local cjson = require "cjson"
local slack = require("swiss.slack")

if signingsecret == nil then
local http = require "resty.http"
local b64 = require("ngx.base64")
local token = cjson.decode(ngx.location.capture('/accesstoken').body).access_token
local httpc = http.new()
local access_token = cjson.decode(ngx.location.capture('/accesstoken').body).access_token
local secretmanager = require("swiss.secretmanager")
local secretlocation = "https://secretmanager.googleapis.com/v1/${SLACK_SIGNING_SECRET}:access"
ngx.log(ngx.WARN, "fetching secret from: " .. secretlocation)
ngx.log(ngx.WARN, "fetching token: " .. token)
local res, err = httpc:request_uri(
secretlocation,
{
headers = {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. token
},
ssl_verify = false
}
)
signingsecret, err = secretmanager.fetch(secretlocation, access_token)

if err ~= nil then
ngx.status = 500
ngx.log(ngx.ERR, "Error fetching SLACK_SIGNING_SECRET: " .. err)
ngx.say("Error fetching SLACK_SIGNING_SECRET: ", err)
elseif res.status == 200 then
local content = cjson.decode(res.body)
signingsecret = b64.decode_base64url(content.payload.data)
else
ngx.status = 500
ngx.log(ngx.ERR, "Error fetching SLACK_SIGNING_SECRET: " .. res.body)
ngx.say("Error fetching SLACK_SIGNING_SECRET: ", res.body)
end
ngx.log(ngx.ERR, "Error fetching secret: " .. err)
ngx.say("Error fetching secret: ", err)
return ngx.exit(500)
end
end

if signingsecret == nil then
return ngx.exit(500)
else
-- Verify
local hmac = require "resty.hmac"
local hmac_sha256 = hmac:new(signingsecret, hmac.ALGOS.SHA256)
local version = "v0"
local timestmap = ngx.req.get_headers()["X-Slack-Request-Timestamp"]
local basestring = version .. ":" .. timestmap .. ":" .. ngx.req.get_body_data()
local mac = "v0=" .. hmac_sha256:final(basestring, true)
if mac ~= ngx.req.get_headers()["X-Slack-Signature"] then
local msg = "Failed signature check: " ..
ngx.req.get_headers()["X-Slack-Signature"] ..
" did not match " .. mac
ngx.status = 500
ngx.log(ngx.ERR, msg)
ngx.say(msg)
return ngx.exit(500)
end
elseif not slack.isAuthentic(ngx.req, signingsecret) then
return ngx.exit(403)
end

local get, post, files = require "resty.reqargs"()
Expand All @@ -265,21 +240,84 @@ server {
}
}

location /slack/event/ {
# https://api.slack.com/interactivity/slash-commands#app_command_handling
rewrite_by_lua_block {
ngx.req.read_body()
local cjson = require "cjson"
local slack = require("swiss.slack")
local event = cjson.decode(ngx.req.get_body_data())
if event.type == "url_verification" then
-- https://api.slack.com/events-api#prepare
ngx.status = 200
ngx.say(event.challenge)
return ngx.exit(200)
end

if signingsecret == nil then
local access_token = cjson.decode(ngx.location.capture('/accesstoken').body).access_token
local secretmanager = require("swiss.secretmanager")
local secretlocation = "https://secretmanager.googleapis.com/v1/${SLACK_SIGNING_SECRET}:access"
signingsecret, err = secretmanager.fetch(secretlocation, access_token)

if err ~= nil then
ngx.status = 500
ngx.log(ngx.ERR, "Error fetching secret: " .. err)
ngx.say("Error fetching secret: ", err)
return ngx.exit(500)
end
end

if signingsecret == nil then
return ngx.exit(500)
elseif not slack.isAuthentic(ngx.req, signingsecret) then
return ngx.exit(403)
end


-- Create a signal request to camunda
local signal = {
name = "event",
variables = {}
}

-- Encode the event json in a JSON string
signal.variables["event"] = {
type = "String",
value = cjson.encode(event.event)
}

-- Encode the envelope values flat
local strings = {"token", "team_id", "api_app_id", "type", "event_id"}
for i, key in ipairs(strings) do
signal.variables[key] = {
type = "String",
value = event[key]
}
end
-- todo event_time

local new_body = cjson.encode(signal)
ngx.log(ngx.WARN, "new_body: " .. new_body)
ngx.req.set_body_data(new_body)
ngx.req.set_header("Content-Type", "application/json")
ngx.req.set_uri("/wal/engine-rest/signal", true)
}
}

# The WAL takes a request, places in an envelope and publishes it to pubusb
location /wal/ {
internal;
content_by_lua_block {

ngx.log(ngx.WARN, "Wal")

ngx.req.read_body()
local cjson = require "cjson"
local b64 = require("ngx.base64")
-- TODO, access token requires unwrapping
local upstreamtoken = cjson.decode(ngx.location.capture('/accesstoken').body).access_token
ngx.req.read_body()
local body = ngx.req.get_body_data() -- Might be nil
ngx.log(ngx.WARN, "wal body: " .. body)
-- local headers = ngx.req.get_headers()

local envelope = {
messages = {
Expand Down
32 changes: 32 additions & 0 deletions google_cloud/openresty-beyondcorp/files/swiss/secretmanager.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
local _M = {
_VERSION = '0.01',
}
local cjson = require "cjson"
local http = require "resty.http"
local b64 = require("ngx.base64")

function _M.fetch(location, access_token)
local httpc = http.new()
local secretlocation = location
ngx.log(ngx.WARN, "fetching secret from: " .. secretlocation)
local res, err = httpc:request_uri(
secretlocation,
{
headers = {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer " .. access_token
},
ssl_verify = false
}
)
if err ~= nil then
return nil, err
elseif res.status == 200 then
local content = cjson.decode(res.body)
return b64.decode_base64url(content.payload.data), nil
else
return nil, res.body
end
end

return _M
29 changes: 29 additions & 0 deletions google_cloud/openresty-beyondcorp/files/swiss/slack.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
local hmac = require "resty.hmac"
local hmacs = {}
local version = "v0"
local err

local _M = {
_VERSION = '0.01',
}

function _M.isAuthentic(request, signingsecret)
if hmacs[signingsecret] == nil then
hmacs[signingsecret] = hmac:new(signingsecret, hmac.ALGOS.SHA256)
end

local hmac_sha256 = hmacs[signingsecret]
local timestamp = request.get_headers()["X-Slack-Request-Timestamp"]
local signature = request.get_headers()["X-Slack-Signature"]
local body = request.get_body_data()
if body == nil or timestamp == nil or signature == nil then
return false
end

local basestring = version .. ":" .. timestamp .. ":" .. body
local mac = version .. "=" .. hmac_sha256:final(basestring, true)
hmac_sha256:reset()
return mac == signature
end

return _M
15 changes: 13 additions & 2 deletions google_cloud/openresty-beyondcorp/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ resource "local_file" "login" {
filename = "${path.module}/.build/login"
}

# Copy files into .build directory
resource "template_dir" "swiss" {
source_dir = "${path.module}/files/swiss"
destination_dir = "${path.module}/.build/swiss"
}

# Create a zip just to generate a sha
data "archive_file" "swiss" {
type = "zip"
source_dir = "${path.module}/.build/swiss"
output_path = "/tmp/swiss.zip"
}

# Cloud Run Openresty
resource "google_cloud_run_service" "openresty" {
name = "openresty"
Expand Down Expand Up @@ -123,14 +136,12 @@ resource "google_pubsub_subscription" "httpwal" {
topic = google_pubsub_topic.httpwal.name

ack_deadline_seconds = 120

push_config {
push_endpoint = "${local.service_url}/wal-playback/"

oidc_token {
service_account_email = google_service_account.openresty.email
}

attributes = {
x-goog-version = "v1"
}
Expand Down
11 changes: 5 additions & 6 deletions google_cloud/openresty-beyondcorp/test/dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ while :
do
# Generate local artifacts
terraform apply \
-target=local_file.login \
-target=local_file.config \
-target=template_dir.swiss \
-target=local_file.dockerfile \
-target=local_file.config \
--auto-approve
docker-compose build
# Run local container
docker-compose up
done
docker-compose build # Rebuild local image
docker-compose up # Run local container
done

0 comments on commit 07a4b3a

Please sign in to comment.