Skip to content

Commit

Permalink
Add a HTTPS proxy for concourse on GCP (#62)
Browse files Browse the repository at this point in the history
* Add a HTTPS proxy for concourse on GCP using a VIP and self signed certificate

* Add letsencrypt support when concourse exposed on public IP

* Force to use HTTPS

* Update the documentation

* Create a specific deployment for ingress

* Fine tuning and hotfixes
  • Loading branch information
calj authored and Louis committed Oct 20, 2017
1 parent cd7a1c1 commit fdc7219
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 85 deletions.
46 changes: 44 additions & 2 deletions lib/kite/render.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,44 @@ class Render < Base

include Kite::Helpers

no_commands do
def ingress_db_file
"config/ingress.yml"
end

def ingress_db
@db ||= YAML.load(File.read(ingress_db_file)) rescue {}
end

def ingress_db_save!
create_file ingress_db_file, YAML.dump(ingress_db), force: true
end

def ingress_add_entry(hostname, upstreams, args = {})
raise "upstreams argument should be an array" unless upstreams.is_a?(Array)
args[:port] ||= 80
args[:protocol] ||= "http"
ingress_db[hostname] = {
upstreams: upstreams,
port: args[:port],
protocol: args[:protocol],
}
ingress_db_save!
end
end

desc "manifest <type>", "Renders a manifest of selected type"
long_desc <<-LONGDESC
Available types:
\x5 BOSH Render Bosh environement
\x5 CONCOURSE Render Concourse deployment
\x5 VAULT Render Vault deployment
\x5 INGRESS Render Ingress deployment
LONGDESC
method_option :cloud, type: :string, desc: "Cloud provider", enum: %w{aws gcp}, required: true
# Render a manifest of selected type based on <b>config/cloud.yml</b> and <b>terraform apply</b> results
def manifest(type)
type = type.downcase
say "Rendering #{type} manifest", :green
@values = parse_cloud_config
@tf_output = parse_tf_state('terraform/terraform.tfstate') if options[:cloud] == 'aws'
Expand All @@ -18,6 +52,9 @@ def manifest(type)
@private_subnet = IPAddr.new(@values['gcp']['subnet_cidr']).to_range.to_a
end

@static_ip_vault = @private_subnet[11].to_s
@static_ips_concourse = [@private_subnet[12]].map(&:to_s)

case type
when "bosh"
directory("#{options[:cloud]}/deployments/bosh", 'deployments/bosh')
Expand All @@ -31,15 +68,20 @@ def manifest(type)
copy_file("#{options[:cloud]}/docs/concourse.md", "docs/concourse.md")
template("#{options[:cloud]}/bin/concourse-deploy.sh.tt", "bin/concourse-deploy.sh")
chmod('bin/concourse-deploy.sh', 0755)
ingress_add_entry(@values['concourse']['hostname'], @static_ips_concourse, port: 8080)

when "vault"
template("#{options[:cloud]}/deployments/vault/vault.yml.erb", "deployments/vault/vault.yml")
copy_file("#{options[:cloud]}/docs/vault.md", "docs/vault.md")
template("#{options[:cloud]}/bin/vault-deploy.sh.tt", "bin/vault-deploy.sh")
chmod('bin/vault-deploy.sh', 0755)
ingress_add_entry(@values['vault']['hostname'], [@static_ip_vault], port: 8200)

when "nginx"
template("#{options[:cloud]}/deployments/nginx/nginx.yml.erb", "deployments/nginx/nginx.yml")
when "ingress"
template("#{options[:cloud]}/deployments/ingress/ingress.yml.erb", "deployments/ingress/ingress.yml")
copy_file("#{options[:cloud]}/docs/ingress.md", "docs/ingress.md")
template("#{options[:cloud]}/bin/ingress-deploy.sh.tt", "bin/ingress-deploy.sh")
chmod('bin/ingress-deploy.sh', 0755)

else
say "Manifest type not specified"
Expand Down
13 changes: 10 additions & 3 deletions tpl/gcp/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
## GCP Cloud
# GCP Cloud

### Setup
## Setup

### Prerequisites
Set path to your service account credentials:
```
export GOOGLE_CREDENTIALS=*~/credentials/service-account.json*
```


### Setup the basic infrastructure and bastion
Apply terraform code
```
pushd terraform && terraform init && terraform apply && popd
Expand All @@ -16,20 +17,26 @@ pushd terraform && terraform init && terraform apply && popd
[Note]
To destroy Bastion later, use `terraform destroy -target google_compute_instance.bastion`

### Setup BOSH
Render BOSH manifest and related files
```
kite render manifest bosh --cloud gcp
```

Prepare BOSH environment using instructions from [docs/bosh.md](docs/bosh.md)

### Setup VAULT
Render Vault deployment
```
kite render manifest vault --cloud gcp
```

Follow instructions from [docs/vault.md](docs/vault.md) to deploy Vault

### Setup CONCOURSE
[Note]
To expose concourse publicly, you must create first (manually) a virtual IP in GCP and create a DNS A entry for the hostname for this IP. Set the IP into config/cloud.yml (concourse.vip).

Render Concourse manifest
```
kite render manifest concourse --cloud gcp
Expand Down
11 changes: 8 additions & 3 deletions tpl/gcp/bin/base/setup-tunnel.sh.tt
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#!/usr/bin/env bash

pushd terraform
BASTION_IP="$(terraform output bastion_ip)"
popd

ssh -D 5000 -fNC kite@$BASTION_IP -i <%= @values['kite']['private_key_path'] %>

export BOSH_ALL_PROXY=socks5://localhost:5000
if [[ -z "${BASTION_IP}" ]]; then
echo "Something goes wrong, please check terraform environement" 1>&2
false
else
ssh -D 5000 -fNC kite@${BASTION_IP} -i ~/.ssh/kite.key
export BOSH_ALL_PROXY=socks5://localhost:5000
fi
7 changes: 7 additions & 0 deletions tpl/gcp/bin/ingress-deploy.sh.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash

set -xe

bosh -e <%= @values['bosh']['name'] %> upload-release https://github.com/cloudfoundry-community/nginx-release/releases/download/v1.12.1/nginx-1.12.1.tgz

bosh -e <%= @values['bosh']['name'] %> -d ingress deploy deployments/ingress/ingress.yml
18 changes: 15 additions & 3 deletions tpl/gcp/deployments/bosh/cloud-config.yml.tt
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,22 @@ vm_types:
root_disk_size_gb: 20
root_disk_type: pd-ssd

- name: ingress
cloud_properties:
machine_type: g1-small
root_disk_size_gb: 20
root_disk_type: pd-ssd
tags:
- http-server
- https-server

- name: worker
cloud_properties:
machine_type: n1-standard-4
machine_type: n1-standard-2
root_disk_size_gb: 100
root_disk_type: pd-ssd
tags:
- no-ip

# vm_extensions:
# - name: concourse-lb
Expand All @@ -27,10 +38,12 @@ compilation:
reuse_compilation_vms: true
az: z1
cloud_properties:
machine_type: n1-standard-4
machine_type: n1-standard-2
root_disk_size_gb: 100
root_disk_type: pd-ssd
preemptible: true
tags:
- no-ip

networks:
- name: public
Expand All @@ -46,7 +59,6 @@ networks:
subnetwork_name: <%= @values['gcp']['subnet_name'] %>
ephemeral_external_ip: false
tags:
- no-ip
- platform-internal
- concourse-public
- concourse-internal
Expand Down
14 changes: 9 additions & 5 deletions tpl/gcp/deployments/concourse/concourse.yml.tt
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ instance_groups:
stemcell: trusty
networks:
- name: public
static_ips: [<%= @private_subnet[12] %>]
static_ips: <%= @static_ips_concourse %>
default: [dns, gateway]

jobs:
- name: atc
release: concourse
properties:
bind_port: 80
bind_port: 8080
external_url: <%= @values['concourse']['url'] %>
basic_auth_username: <%= @values['concourse']['auth_username'] %>
basic_auth_password: ((auth_password))
Expand All @@ -33,7 +33,7 @@ instance_groups:
backend: token
client_token: ((vault_token))
path_prefix: /concourse
url: "http://<%= @private_subnet[11] %>:8200" # expecting Vault to be deployed first
url: "http://<%= @static_ip_vault %>:8200" # expecting Vault to be deployed first

postgresql_database: &atc_db atc

Expand All @@ -47,7 +47,9 @@ instance_groups:
azs: [z1]
stemcell: trusty
persistent_disk_type: database
networks: [{name: public}]
networks:
- name: public
default: [dns, gateway]
jobs:
- name: postgresql
release: concourse
Expand All @@ -62,7 +64,9 @@ instance_groups:
vm_type: worker
azs: [z1]
stemcell: trusty
networks: [{name: public}]
networks:
- name: public
default: [dns, gateway]
jobs:
- name: groundcrew
release: concourse
Expand Down
107 changes: 107 additions & 0 deletions tpl/gcp/deployments/ingress/ingress.yml.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
name: ingress

releases:
- name: nginx
version: latest

instance_groups:
- name: ingress
instances: 1
vm_type: ingress-tiny
azs: [z1]
stemcell: trusty
networks:
- name: public
static_ips: [<%= @private_subnet[13] %>]
default: [dns, gateway]

- name: vip
static_ips: [<%= @values['ingress']['vip'] %>]

jobs:
- name: nginx
release: nginx
properties:
nginx_conf: |
worker_processes 1;
error_log /var/vcap/sys/log/nginx/error.log info;
events {
worker_connections 1024;
}

http {
include /var/vcap/packages/nginx/conf/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server_names_hash_bucket_size 64;

server {
listen 80;
return 301 https://$host$request_uri;
}
<% ingress_db.each do |hostname, config| %>
<% upstream_name = hostname.gsub('.', '-') %>
upstream <%= upstream_name %> {
<%- config[:upstreams].each do |upstream| -%>
server <%= upstream %>:<%= config[:port] %>;
<%- end -%>
}
server {
listen 443;
server_name <%= hostname %>;
ssl_certificate_key /var/vcap/jobs/nginx/etc/<%= hostname %>/key.pem;
ssl_certificate /var/vcap/jobs/nginx/etc/<%= hostname %>/cert.pem;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;

access_log /var/vcap/sys/log/nginx/<%= hostname %>-access.log;
error_log /var/vcap/sys/log/nginx/<%= hostname %>-error.log;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

proxy_pass <%= config[:protocol] %>://<%= upstream_name%>;
proxy_read_timeout 90;
}
}
<% end %>
}

pre_start: |
#!/bin/bash
set -x
source /etc/profile
export HOME=/root
export USER=root
echo "Running pre_start script as ${USER} with ${SHELL} with home ${HOME}"
if [[ ! -f ${HOME}/.acme.sh/acme.sh.env ]]; then
curl -s https://get.acme.sh | sh
fi
source ${HOME}/.acme.sh/acme.sh.env
<% ingress_db.each do |hostname, config| -%>
mkdir -p /var/vcap/jobs/nginx/etc/<%= hostname %>/
${HOME}/.acme.sh/acme.sh --issue --tls -d <%= hostname %>
${HOME}/.acme.sh/acme.sh --install-cert -d <%= hostname %> \
--key-file /var/vcap/jobs/nginx/etc/<%= hostname %>/key.pem \
--fullchain-file /var/vcap/jobs/nginx/etc/<%= hostname %>/cert.pem
<%- end -%>

stemcells:
- alias: trusty
os: ubuntu-trusty
version: latest

update:
canaries: 1
max_in_flight: 1
serial: false
canary_watch_time: 1000-60000
update_watch_time: 1000-60000
Loading

0 comments on commit fdc7219

Please sign in to comment.