Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup proxy configuration #1440

Merged
merged 4 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 21 additions & 29 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,43 +18,35 @@ jobs:
- run: cp config/test.circleci.exs config/test.local.exs
- restore_cache:
keys:
- v4-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
- v4-yarn-cache-{{ .Branch }}
- v4-yarn-cache
- v5-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
- v5-yarn-cache-{{ .Branch }}
- v5-yarn-cache
- restore_cache:
keys:
- v4-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
- v4-mix-cache-{{ .Branch }}
- v4-mix-cache
- v5-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
- v5-mix-cache-{{ .Branch }}
- restore_cache:
keys:
- v4-build-cache-{{ .Branch }}
- v4-build-cache
- v5-build-cache-{{ .Branch }}
- run: mix do deps.get, compile
- run: cd assets && yarn && cd ..
- save_cache:
key: v4-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
key: v5-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
paths: "assets/node_modules"
- save_cache:
key: v4-yarn-cache-{{ .Branch }}
key: v5-yarn-cache-{{ .Branch }}
paths: "assets/node_modules"
- save_cache:
key: v4-yarn-cache-{{ .Branch }}
key: v5-yarn-cache-{{ .Branch }}
paths: "assets/node_modules"
- save_cache:
key: v4-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
key: v5-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
paths: "deps"
- save_cache:
key: v4-mix-cache-{{ .Branch }}
key: v5-mix-cache-{{ .Branch }}
paths: "deps"
- save_cache:
key: v4-mix-cache
paths: "deps"
- save_cache:
key: v4-build-cache-{{ .Branch }}
paths: "_build"
- save_cache:
key: v4-build-cache
key: v5-build-cache-{{ .Branch }}
paths: "_build"

lint:
Expand All @@ -69,11 +61,11 @@ jobs:
- run: mix local.rebar --force
- run: cp config/test.circleci.exs config/test.local.exs
- restore_cache:
key: v4-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
key: v5-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
- restore_cache:
key: v4-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
key: v5-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
- restore_cache:
key: v4-build-cache-{{ .Branch }}
key: v5-build-cache-{{ .Branch }}
- run: mix deps.get
- run: mix compile --force
- run: mix deps.audit --ignore-package-names sweet_xml
Expand Down Expand Up @@ -106,11 +98,11 @@ jobs:
- run: mix clean
- run: cp config/test.circleci.exs config/test.local.exs
- restore_cache:
key: v4-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
key: v5-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
- restore_cache:
key: v4-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
key: v5-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
- restore_cache:
key: v4-build-cache-{{ .Branch }}
key: v5-build-cache-{{ .Branch }}
- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
Expand All @@ -135,11 +127,11 @@ jobs:
- run: mix local.rebar --force
- run: cp config/test.circleci.exs config/test.local.exs
- restore_cache:
key: v4-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
key: v5-yarn-cache-{{ .Branch }}-{{ checksum "assets/yarn.lock" }}
- restore_cache:
key: v4-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
key: v5-mix-cache-{{ .Branch }}-{{ checksum "mix.lock" }}
- restore_cache:
key: v4-build-cache-{{ .Branch }}
key: v5-build-cache-{{ .Branch }}
- run: mix deps.get
- run: cd assets && yarn run build && cd ..
- run: mix phx.digest
Expand Down
5 changes: 3 additions & 2 deletions config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ config :challenge_gov, ChallengeGov.GovDelivery,
config :challenge_gov, ChallengeGov.Mailer,
from: System.get_env("MAILER_FROM_ADDRESS"),
adapter: Bamboo.SMTPAdapter,
server: "smtp-relay.gmail.com",
server: System.get_env("SMTP_SERVER"),
hostname: System.get_env("HOST"),
port: 25,
port: String.to_integer(System.get_env("SMTP_PORT") || "25"),
tls_verify: :verify_none,
tls: :never,
ssl: false,
retries: 1
Expand Down
4 changes: 4 additions & 0 deletions docs/cloud_gov.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ Learn more generally about [cloud.gov](https://cloud.gov/), and specifically und
The app will run database migrations and seeds when booting. Background tasks are processed with Quantum and do not require any additional running processes
## Proxy
This app expects the configuration of an egress proxy. The configuration is managed locally with a sidecar as well as through the deployment of an egress proxy application configured in the platform codebase https://github.com/GSA/Challenge_platform
## SSH
Disable SSH for any sensitive environment when not in use. This can be done through the cloud.gov web interface.
Expand Down
6 changes: 5 additions & 1 deletion docs/configuration_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
| AWS_ACCESS_KEY_ID | Access key for S3, provided as a Cloud.gov Service | |
| AWS_SECRET_ACCESS_KEY | Secret Access key for S3, provided as a Cloud.gov Service | |
| BUCKET_NAME | Bucket Name for S3, provided as a Cloud.gov Service | |
| CHALLENGE_OWNER_ASSUMED_TLDS | By default, only .gov email addresses are assumed to want the Challenge Manager role, this allows other government TLD values to also be considered as wanting the Challenge Manager role | .mil |
| CHALLENGE_OWNER_ASSUMED_TLDS | By default, only .gov email addresses are assumed to want the Challenge Manager role, this allows other government TLD values to also be considered as wanting the Challenge Manager role | .mil |
| DATABASE_URL | The standard formatted postgres URL composed from the components of username, password, hostname, and database name, as provided by the Cloud.gov RDS service | postgres://username:password@hostname:port/database |
| GOV_DELIVERY_ACCOUNT_CODE | The GovDelivery account code | |
| GOV_DELIVERY_API_PASSWORD | The password of the API account with admin permission for the API | |
Expand All @@ -22,6 +22,7 @@
| GOV_DELIVERY_TOPIC_SUBSCRIBE_URL | The URL that the topic code gets added to for each challenge to be subscribed to | |
| GOV_DELIVERY_URL | The base API url for the GovDelivery API | |
| HOST | The external DNS name of the running portal | portal.challenge.gov |
| LOCAL_PROXY_HOST | The local sidecar proxy that will relay to the egress proxy | 127.0.0.1 |
| LOGIN_CLIENT_ID | The login client ID for the application in Login.gov | urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:challenge_gov |
| LOGIN_PRIVATE_KEY_PASSWORD | The password to decrypt the private key used in the Login.gov OpenID connect flow | password |
| LOGIN_PUBLIC_KEY_PATH | The path within the code repository to the provide key for the application to use with Login.gov | environment_key.pem |
Expand All @@ -30,7 +31,10 @@
| LOG_RETENTION_IN_DAYS | Number of days of security audit logs to keep in the database | 90 |
| MAILER_FROM_ADDRESS | The from/reply-to address for transactional email sent by the system | support@challenge.gov |
| MIX_ENV | The environment mode for the running application, should always be prod | prod |
| PROXYROUTE | The fully qualified URL for the upstream egress proxy with protocol, authentication, domain, and port. Used by the caddy sidecar | |
| RECAPTCHA_SECRET_KEY | Google reCaptcha 3 secret key | |
| RECAPTCHA_SITE_KEY | Google reCaptcha 3 public site key | |
| SECRET_KEY_BASE | Random seed used to encrypt secrets (cookies) for session management between the application and the browser | |
| SESSION_TIMEOUT_IN_MINUTES | Amount of idle time before the system logs a user out | 15 |
| SMTP_SERVER | The DNS or IP address of the SMTP server to connect to. May be a TCP relay proxy | |
| SMTP_PORT | The port of the SMTP server to connect to. May be a TCP relay proxy | |
19 changes: 18 additions & 1 deletion lib/challenge_gov/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule ChallengeGov.Application do
# Start the PubSub system
{Phoenix.PubSub, name: ChallengeGov.PubSub},
ChallengeGov.Repo,
{Finch, name: ChallengeGov.HTTPClient},
finch_config(System.get_env("LOCAL_PROXY_HOST")),
Web.Endpoint,
ChallengeGov.Scheduler,
ChallengeGov.Telemetry,
Expand All @@ -34,4 +34,21 @@ defmodule ChallengeGov.Application do
defp oban_config do
Application.get_env(:challenge_gov, Oban)
end

defp finch_config(nil), do: {Finch, name: ChallengeGov.HTTPClient}
defp finch_config(""), do: {Finch, name: ChallengeGov.HTTPClient}

defp finch_config(proxy_host) do
{Finch,
name: ChallengeGov.HTTPClient,
pools: %{
:default => [
size: 5,
conn_opts: [
protocols: [:http1],
proxy: {:http, proxy_host, 8080, []}
]
]
}}
end
end
5 changes: 5 additions & 0 deletions manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ applications:
<<: *defaults
instances: 1
disk_quota: 6GB
sidecars:
- name: local-proxy
process_types: [ 'web' ]
command: ./proxy/sidecar_start.sh
memory: 64M
env:
MIX_ENV: prod
STACK: heroku-22
Expand Down
48 changes: 48 additions & 0 deletions proxy/.profile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh

# Despite the temptation to use #!/bin/bash, we want to keep this file as as
# POSIX sh-compatible as possible. This is to facilitate testing the .profile
# under Alpine, which doesn't have /bin/bash, but does have ash (which is itself
# a flavor of busybox).
ENABLE_ASH_BASH_COMPAT=1

set -e

# Ensure there's only one entry per line, and leave no whitespace
PROXY_DENY=$( echo -n "$PROXY_DENY" | sed 's/^\S/ &/' | sed 's/\ /\n/g' | sed '/^\s*$/d' )
PROXY_ALLOW=$( echo -n "$PROXY_ALLOW" | sed 's/^\S/ &/' | sed 's/\ /\n/g' | sed '/^\s*$/d' )

# Append to the appropriate files
echo -n "$PROXY_DENY" > deny.acl
echo -n "$PROXY_ALLOW" > allow.acl

# Newline Terminate Non-Empty File If Not Already aka ntnefina
# https://stackoverflow.com/a/10082466/17138235
#
# It's unclear if this works properly under Alpine because it uses ANSI-C
# quoting; that needs more testiing. However, if caddy complains about a blank
# in the file, you know why!
ntnefina() {
if [ -s "$1" ] && [ "$(tail -c1 "$1"; echo x)" != $'\nx' ]; then
echo "" >> "$1"
fi
}

ntnefina deny.acl
ntnefina allow.acl

# Make it easy to run curl tests on ourselves
https_proxy="https://$PROXY_USERNAME:$PROXY_PASSWORD@$(echo "$VCAP_APPLICATION" | jq .application_uris[0] | sed 's/"//g'):61443"
export https_proxy

# Make open ports configurable via the PROXY_PORTS environment variable.
# For example "80 443 22 61443". Default to 443 only.
if [ -z "${PROXY_PORTS}" ]; then
PROXY_PORTS="443"
fi
export PROXY_PORTS

echo
echo
echo "The proxy connection URL is:"
echo " $https_proxy"
25 changes: 25 additions & 0 deletions proxy/Caddyfile.local.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
debug
log {
format console
level INFO
}
auto_https off
}

:8888 {
route {
forward_proxy {
acl {
allow all
}
ports 80 443 61443
upstream $PROXYROUTE
}
}
log {
format json
level INFO
output stdout
}
}
Binary file added proxy/caddy
Binary file not shown.
Binary file added proxy/envsubst
Binary file not shown.
5 changes: 5 additions & 0 deletions proxy/sidecar_start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
echo "Updating Caddy config"
./proxy/envsubst < ./proxy/Caddyfile.local.tmpl > ./proxy/Caddyfile.local

echo "Starting Caddy"
exec ./proxy/caddy run --config ./proxy/Caddyfile.local