Skip to content

Commit

Permalink
feat: Add www.iab.org K8s configuration (#477)
Browse files Browse the repository at this point in the history
* chore: Use k8s/ietfweb as a base for k8s/iabweb

* chore: Change prefix for environment variables to IABWWW_

* chore: Set iabweb as default database name

* chore: Update domain in email settings to iab.org

* chore: Change prefix for environment variables to IABWWW_ (cont)

* chore: Update domain for IABWWW_ALLOWED_HOSTS

* chore: Change K8s namespace to iabwww

* chore: Remove custom nginx config for www.ietf.org

* chore: Change CONTAINER_ROLE to iabweb

* chore: Update placeholder for IABWWW_DJANGO_SECRET_KEY

* chore: Remove volumes not needed

* chore: Update value of IABWWW_CSRF_TRUSTED_ORIGINS (commented out)

but for consistency

* chore: Add www-tmp volume

* chore: Remove volume mount for dt-vol

* chore: Use different memcached key prefix for iabweb

* chore: Use External Secrets for iabweb

* chore: Allocate less memory to memcached for iabweb

* chore: Apply iabwww- prefix to volume and config map names

* chore: Remove iabwww- prefix from config map

as already handled by namePrefix

* chore: Clean up config map

* chore: Remove placeholder for secret key from config map

* chore: Add secrets.yaml (placeholders)

* chore: Remove config map in favour of external secret
  • Loading branch information
microamp authored Aug 5, 2024
1 parent 5fb5b2e commit b222992
Show file tree
Hide file tree
Showing 8 changed files with 434 additions and 0 deletions.
12 changes: 12 additions & 0 deletions k8s/iabweb/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace: iabwww
namePrefix: iabwww-
configMapGenerator:
- name: files-cfgmap
files:
- local.py
- supervisord.conf
- nginx-default.conf
- nginx.conf
resources:
- memcached.yaml
- wagtail.yaml
111 changes: 111 additions & 0 deletions k8s/iabweb/local.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Copyright The IETF Trust 2007-2024, All Rights Reserved
# -*- coding: utf-8 -*-

from email.utils import parseaddr
import os

def _multiline_to_list(s):
"""Helper to split at newlines and conver to list"""
return [item.strip() for item in s.split("\n")]


DEFAULT_FROM_EMAIL = "donotreply@iab.org"
SERVER_EMAIL = "donotreply@iab.org"
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = os.environ.get("IABWWW_EMAIL_HOST", "localhost")
EMAIL_PORT = int(os.environ.get("IABWWW_EMAIL_PORT", "2025"))

# Secrets
_SECRET_KEY = os.environ.get("IABWWW_DJANGO_SECRET_KEY", None)
if _SECRET_KEY is not None:
SECRET_KEY = _SECRET_KEY
else:
raise RuntimeError("IABWWW_DJANGO_SECRET_KEY must be set")


_CSRF_TRUSTED_ORIGINS_STR = os.environ.get("IABWWW_CSRF_TRUSTED_ORIGINS", None)
if _CSRF_TRUSTED_ORIGINS_STR is not None:
CSRF_TRUSTED_ORIGINS = _multiline_to_list(_CSRF_TRUSTED_ORIGINS_STR)

FILE_UPLOAD_PERMISSIONS = 0o664
_WAGTAILADMIN_BASE_URL = os.environ.get("WAGTAILADMIN_BASE_URL", None)
if _WAGTAILADMIN_BASE_URL is not None:
WAGTAILADMIN_BASE_URL = _WAGTAILADMIN_BASE_URL
else:
raise RuntimeError("WAGTAILADMIN_BASE_URL must be present")

# Set DEBUG if IABWWW_DEBUG env var is the word "true"
DEBUG = os.environ.get("IABWWW_DEBUG", "false").lower() == "true"

# IABWWW_ALLOWED_HOSTS env var is a comma-separated list of allowed hosts
_ALLOWED_HOSTS_STR = os.environ.get("IABWWW_ALLOWED_HOSTS", None)
if _ALLOWED_HOSTS_STR is not None:
ALLOWED_HOSTS = _multiline_to_list(_ALLOWED_HOSTS_STR)

DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"HOST": os.environ.get("IABWWW_DB_HOST", "db"),
"PORT": os.environ.get("IABWWW_DB_PORT", "5432"),
"NAME": os.environ.get("IABWWW_DB_NAME", "iabweb"),
"USER": os.environ.get("IABWWW_DB_USER", "django"),
"PASSWORD": os.environ.get("IABWWW_DB_PASS", ""),
"CONN_MAX_AGE": 600, # number of seconds database connections should persist for
},
}

# IABWWW_ADMINS is a newline-delimited list of addresses parseable by email.utils.parseaddr
_admins_str = os.environ.get("IABWWW_ADMINS", None)
if _admins_str is not None:
ADMINS = [parseaddr(admin) for admin in _multiline_to_list(_admins_str)]
else:
raise RuntimeError("IABWWW_ADMINS must be set")

# Leave IABWWW_MATOMO_SITE_ID unset to disable Matomo reporting
if "IABWWW_MATOMO_SITE_ID" in os.environ:
MATOMO_DOMAIN_PATH = os.environ.get("IABWWW_MATOMO_DOMAIN_PATH", "analytics.ietf.org")
MATOMO_SITE_ID = os.environ.get("IABWWW_MATOMO_SITE_ID", None)
MATOMO_DISABLE_COOKIES = True

# Duplicating production cache from settings.py and using it whether we're in production mode or not
MEMCACHED_HOST = os.environ.get("IABWWW_MEMCACHED_SERVICE_HOST", "127.0.0.1")
MEMCACHED_PORT = os.environ.get("IABWWW_MEMCACHED_SERVICE_PORT", "11211")
MEMCACHED_KEY_PREFIX = "iab"
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": f"{MEMCACHED_HOST}:{MEMCACHED_PORT}",
"KEY_PREFIX": MEMCACHED_KEY_PREFIX,
},
"sessions": {
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": f"{MEMCACHED_HOST}:{MEMCACHED_PORT}",
"KEY_PREFIX": MEMCACHED_KEY_PREFIX,
},
"dummy": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"},
}

# Logging

LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"mail_admins": {
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler",
},
},
"loggers": {
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
"django.security": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
},
}
74 changes: 74 additions & 0 deletions k8s/iabweb/memcached.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: memcached
spec:
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
app: memcached
template:
metadata:
labels:
app: memcached
spec:
securityContext:
runAsNonRoot: true
containers:
- image: "quay.io/prometheus/memcached-exporter:v0.14.3"
imagePullPolicy: IfNotPresent
name: memcached-exporter
ports:
- name: metrics
containerPort: 9150
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsUser: 65534 # nobody
runAsGroup: 65534 # nobody
- image: "memcached:1.6-alpine"
imagePullPolicy: IfNotPresent
args: ["-m", "256"]
name: memcached
ports:
- name: memcached
containerPort: 11211
protocol: TCP
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
# memcached image sets up uid/gid 11211
runAsUser: 11211
runAsGroup: 11211
dnsPolicy: ClusterFirst
restartPolicy: Always
terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
name: memcached
annotations:
k8s.grafana.com/scrape: "true" # this is not a bool
k8s.grafana.com/metrics.portName: "metrics"
spec:
type: ClusterIP
ports:
- port: 11211
targetPort: memcached
protocol: TCP
name: memcached
- port: 9150
targetPort: metrics
protocol: TCP
name: metrics
selector:
app: memcached
32 changes: 32 additions & 0 deletions k8s/iabweb/nginx-default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
server {
listen 8080 default_server;
listen [::]:8080 default_server;
server_name _;
gzip on;
access_log /dev/stdout;
error_log /dev/stdout warn;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $${keepempty}host;
proxy_set_header X-Forwarded-For $${keepempty}proxy_add_x_forwarded_for;
}
location /media/ {
alias /app/media/;

error_page 404 = @error_redirect;
}
location /static/ {
alias /app/static/;

error_page 404 = @error_redirect;
}
location /robots.txt {
add_header Content-Type text/plain;
return 200 "User-agent: *\nDisallow: /admin/\n";
}
location @error_redirect {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $${keepempty}host;
proxy_set_header X-Forwarded-For $${keepempty}proxy_add_x_forwarded_for;
}
}
53 changes: 53 additions & 0 deletions k8s/iabweb/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
worker_processes auto;
pid /var/lib/nginx/nginx.pid;
error_log /dev/stdout;
include /etc/nginx/modules-enabled/*.conf;

events {
worker_connections 768;
# multi_accept on;
}

http {

##
# Basic Settings
##

sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
# server_tokens off;

# server_names_hash_bucket_size 64;
# server_name_in_redirect off;

include /etc/nginx/mime.types;
default_type application/octet-stream;

##
# SSL Settings
##

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

##
# Logging Settings
##

access_log /dev/stdout;

##
# Gzip Settings
##

gzip on;

##
# Virtual Host Configs
##

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
31 changes: 31 additions & 0 deletions k8s/iabweb/secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: v1
kind: Secret
metadata:
name: secrets-env
type: Opaque
stringData:
IABWWW_ADMINS: |-
Robert Sparks <rjsparks@nostrum.com>
Kesara Rathnayake <kesara@staff.ietf.org>
IABWWW_ALLOWED_HOSTS: ".iab.org" # newline-separated list also allowed
WAGTAILADMIN_BASE_URL: "https://www.iab.org/admin/"

# Outgoing email details
IABWWW_EMAIL_HOST: "iab.mr.ietf.org"
IABWWW_EMAIL_PORT: "10027"

IABWWW_MATOMO_SITE_ID: null # must be present to enable Matomo

# Can also be a newline-separated list
IABWWW_CSRF_TRUSTED_ORIGINS: "https://www.iab.org"

# Database connection details - to be fetched from Vault
# IABWWW_DB_HOST: ""
# IABWWW_DB_NAME: ""
# IABWWW_DB_PASS: ""
# IABWWW_DB_PORT: ""
# IABWWW_DB_USER: ""

# Django secret key - to be fetched from Vault
# IABWWW_DJANGO_SECRET_KEY: ""
17 changes: 17 additions & 0 deletions k8s/iabweb/supervisord.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[supervisord]
nodaemon=true
logfile=/dev/stdout
logfile_maxbytes=0

[program:nginx]
command=nginx -g "daemon off;"
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true

[program:gunicorn]
command=/usr/local/bin/gunicorn --config /app/docker/gunicorn.py ietf.wsgi
directory=/app
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
Loading

0 comments on commit b222992

Please sign in to comment.