Skip to content

Commit 9c36024

Browse files
authored
Initial commit of auth proxy and user management (#154)
* Initial commit of auth proxy and user management Using Ory Kratos and Oathkeeper. Added Zero module parameter to enable or disable. Still need to add proper DB and mail support. Not including oathkeeper rules for now, as since we are using the operator we can define them in the backend project. * Adds licensing info (#157) * user_access: all users to have replicaset access (#158) * user_access: all users to have replicaset access to check rollout status for deployments, permission to list replicaset is needed * typo: fix missing semicolon for sql statement * fixup! typo: fix missing semicolon for sql statement * Add proper creation of auth database, a bunch of refactoring to the db creation process. * Set hostname in kratos flows, a couple other changes from David * Change cors allow to frontend domain
1 parent 40665a6 commit 9c36024

17 files changed

Lines changed: 735 additions & 79 deletions

File tree

Makefile

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
11
SHELL := /bin/bash
2+
CREATE_DB_USERS := $(shell kubectl -n ${PROJECT_NAME} get secrets ${PROJECT_NAME} > /dev/null 2>&1; echo $$?)
23

3-
run:
4+
run: make-apply create-application-user create-auth-user
5+
6+
make-apply:
47
cd $(PROJECT_DIR) && AUTO_APPROVE="-auto-approve" make
5-
kubectl -n ${PROJECT_NAME} get secrets ${PROJECT_NAME} > /dev/null 2>&1 || ( \
6-
export REGION=${region}; \
7-
export SEED=${randomSeed}; \
8-
export PROJECT_NAME=${PROJECT_NAME}; \
9-
export ENVIRONMENT=${ENVIRONMENT}; \
10-
export DATABASE=${database}; \
11-
sh ./db-ops/create-db-user.sh )
8+
9+
create-application-user:
10+
[[ "${CREATE_DB_USERS}" != "0" ]] && \
11+
REGION=${region} \
12+
SEED=${randomSeed} \
13+
PROJECT_NAME=${PROJECT_NAME} \
14+
ENVIRONMENT=${ENVIRONMENT} \
15+
NAMESPACE=${PROJECT_NAME} \
16+
DATABASE_TYPE=${database} \
17+
DATABASE_NAME=${PROJECT_NAME} \
18+
USER_NAME=${PROJECT_NAME} \
19+
CREATE_SECRET=secret-application.yml.tpl \
20+
sh ./db-ops/create-db-user.sh || echo
21+
22+
create-auth-user:
23+
[[ "${CREATE_DB_USERS}" != "0" && "${userAuth}" == "yes" ]] && \
24+
REGION=${region} \
25+
SEED=${randomSeed} \
26+
PROJECT_NAME=${PROJECT_NAME} \
27+
ENVIRONMENT=${ENVIRONMENT} \
28+
NAMESPACE=user-auth \
29+
DATABASE_TYPE=${database} \
30+
DATABASE_NAME=user_auth \
31+
USER_NAME=kratos \
32+
CREATE_SECRET=secret-user-auth.yml.tpl \
33+
sh ./db-ops/create-db-user.sh || echo
1234

1335
summary:
1436
@echo "zero-aws-eks-stack:"

db-ops/create-db-user.sh

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,68 @@ usage () {
77
}
88

99
# check parameters
10-
([[ -z "${REGION}" ]] || \
11-
[[ -z "${SEED}" ]] || \
12-
[[ -z "${PROJECT_NAME}" ]] || \
13-
[[ -z "${ENVIRONMENT}" ]] || \
14-
[[ -z "${DATABASE}" ]] ) && \
15-
echo "Environment variables (REGION/REGION/PROJECT_NAME/ENVIRONMENT/DATABASE) are not set properly. Please have a check." && usage
16-
17-
# docker image with postgres.mysql client
10+
# REGION - AWS region to use
11+
# SEED - Random seed that is part of the name of the AWS secret containing the db master password
12+
# PROJECT_NAME - Name of the project and the k8s namespace containing the database service
13+
# ENVIRONMENT - stage or prod
14+
# NAMESPACE - The target k8s namespace to create and create a secret in
15+
# DATABASE_TYPE - The type of database - mysql, postgres
16+
# DATABASE_NAME - The name of the database to create in the database server
17+
# USER_NAME - The name of the user to create and grant access to the database specified above
18+
# CREATE_SECRET - A template file to render to create a secret
19+
([[ -z "${REGION}" ]] || \
20+
[[ -z "${SEED}" ]] || \
21+
[[ -z "${PROJECT_NAME}" ]] || \
22+
[[ -z "${ENVIRONMENT}" ]] || \
23+
[[ -z "${NAMESPACE}" ]] || \
24+
[[ -z "${DATABASE_TYPE}" ]] || \
25+
[[ -z "${DATABASE_NAME}" ]] || \
26+
[[ -z "${USER_NAME}" ]] || \
27+
[[ -z "${CREATE_SECRET}" ]] ) && \
28+
echo "Some environment variables (REGION, SEED, PROJECT_NAME, ENVIRONMENT, NAMESPACE, DATABASE_TYPE, DATABASE_NAME, USER_NAME, CREATE_SECRET) are not set properly." && usage
29+
30+
# docker image with postgres + mysql clients
1831
DOCKER_IMAGE_TAG=commitdev/zero-k8s-utilities:0.0.3
1932

2033
# database info preparation
21-
DB_ENDPOINT=database.$PROJECT_NAME
22-
DB_NAME=$(aws rds describe-db-instances --region=$REGION --query "DBInstances[?DBInstanceIdentifier=='$PROJECT_NAME-$ENVIRONMENT'].DBName" | jq -r '.[0]')
34+
DB_ENDPOINT=database.${PROJECT_NAME}
35+
DB_NAME=$(echo "${DATABASE_NAME}" | tr -dc 'A-Za-z0-9')
36+
DB_TYPE=${DATABASE_TYPE}
2337
## get rds master
24-
SECRET_ID=$(aws secretsmanager list-secrets --region $REGION --query "SecretList[?Name=='$PROJECT_NAME-$ENVIRONMENT-rds-$SEED'].Name" | jq -r ".[0]")
38+
SECRET_ID=$(aws secretsmanager list-secrets --region ${REGION} --query "SecretList[?Name=='${PROJECT_NAME}-${ENVIRONMENT}-rds-${SEED}'].Name" | jq -r ".[0]")
2539
MASTER_RDS_USERNAME=master_user
26-
MASTER_RDS_PASSWORD=$(aws secretsmanager get-secret-value --region=$REGION --secret-id=$SECRET_ID | jq -r ".SecretString")
40+
MASTER_RDS_PASSWORD=$(aws secretsmanager get-secret-value --region=${REGION} --secret-id=${SECRET_ID} | jq -r ".SecretString")
2741
## get application user/pass
28-
DB_APP_USERNAME=$PROJECT_NAME
29-
DB_APP_PASSWORD=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | base64 | head -c 16)
42+
DB_APP_USERNAME=$(echo "${USER_NAME}" | tr -dc 'A-Za-z0-9')
43+
DB_APP_PASSWORD=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | base64 | head -c 24)
44+
45+
# get correct dsn string for db type
46+
if [[ "${DB_TYPE}" == "postgres" ]]; then
47+
DB_ENDPOINT_FOR_DSN="${DB_ENDPOINT}"
48+
elif [[ "${DB_TYPE}" == "mysql" ]]; then
49+
DB_ENDPOINT_FOR_DSN="tcp(${DB_ENDPOINT})"
50+
fi
3051

3152
# fill in env-vars to db user creation manifest
3253
JOB_ID=$(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8)
33-
eval "echo \"$(cat ./db-ops/job-create-db-$DATABASE.yml.tpl)\"" > ./k8s-job-create-db.yml
34-
# the manifest creates 4 things
35-
# 1. Namespace: db-ops
54+
eval "echo \"$(cat ./db-ops/job-create-db-${DATABASE_TYPE}.yml.tpl)\"" > ./k8s-job-create-db.yml
55+
[[ -z "${CREATE_SECRET}" ]] || eval "echo \"$(cat ./db-ops/${CREATE_SECRET})\"" >> ./k8s-job-create-db.yml
56+
# the manifest creates these things
57+
# 1. Namespaces: db-ops, $NAMESPACE
3658
# 2. Secret in db-ops: db-create-users (with master password, and a .sql file
3759
# 3. Job in db-ops: db-create-users (runs the .sql file against the RDS given master_password from env)
38-
# 4. Secret in Application namespace with DB_USERNAME / DB_PASSWORD
60+
# 4. Secret in $NAMESPACE namespace with DB_USERNAME / DB_PASSWORD
3961

4062
# execution
4163
kubectl apply -f ./k8s-job-create-db.yml
4264
rm -f ./k8s-job-create-db.yml
4365

4466
# clean up
4567
## Deleting the entire db-ops namespace, leaving ONLY application-namespace's secret behind
46-
kubectl -n db-ops wait --for=condition=complete --timeout=10s job db-create-users-${JOB_ID}
68+
kubectl -n db-ops wait --for=condition=complete --timeout=10s job db-create-users-$NAMESPACE-${JOB_ID}
4769
if [ $? -eq 0 ]
48-
then
70+
then
4971
kubectl delete namespace db-ops
50-
else
51-
echo "Failed to create application database user, please see 'kubectl logs -n db-ops -l job-name=db-create-users-${JOB_ID}'"
72+
else
73+
echo "Failed to create application database user, please see 'kubectl logs -n db-ops -l job-name=db-create-users-$NAMESPACE-${JOB_ID}'"
5274
fi

db-ops/job-create-db-mysql.yml.tpl

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,45 @@ apiVersion: v1
22
kind: Namespace
33
metadata:
44
name: db-ops
5+
56
---
67
apiVersion: v1
78
kind: Secret
89
metadata:
910
name: db-create-users
1011
namespace: db-ops
1112
type: Opaque
12-
stringData:
13+
stringData:
14+
RDS_MASTER_PASSWORD: $MASTER_RDS_PASSWORD
1315
create-user.sql: |
14-
DROP USER '$DB_APP_USERNAME';
16+
CREATE DATABASE IF NOT EXISTS $DB_NAME;
17+
DROP USER IF EXISTS '$DB_APP_USERNAME';
1518
CREATE USER '$DB_APP_USERNAME' IDENTIFIED BY '$DB_APP_PASSWORD';
1619
GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_APP_USERNAME';
17-
RDS_MASTER_PASSWORD: $MASTER_RDS_PASSWORD
20+
1821
---
1922
apiVersion: v1
2023
kind: Namespace
2124
metadata:
22-
name: $PROJECT_NAME
23-
---
24-
apiVersion: v1
25-
kind: Secret
26-
metadata:
27-
name: $PROJECT_NAME
28-
namespace: $PROJECT_NAME
29-
type: Opaque
30-
stringData:
31-
DATABASE_USERNAME: $DB_APP_USERNAME
32-
DATABASE_PASSWORD: $DB_APP_PASSWORD
25+
name: $NAMESPACE
26+
3327
---
3428
apiVersion: batch/v1
3529
kind: Job
3630
metadata:
37-
name: db-create-users-$JOB_ID
31+
name: db-create-users-$NAMESPACE-$JOB_ID
3832
namespace: db-ops
3933
spec:
4034
template:
4135
spec:
4236
containers:
4337
- name: create-rds-user
4438
image: $DOCKER_IMAGE_TAG
45-
command:
39+
command:
4640
- sh
47-
args:
48-
- '-c'
49-
- mysql -u$MASTER_RDS_USERNAME -h $DB_ENDPOINT $DB_NAME < /db-ops/create-user.sql
41+
args:
42+
- '-c'
43+
- mysql -u$MASTER_RDS_USERNAME -h $DB_ENDPOINT mysql < /db-ops/create-user.sql
5044
env:
5145
- name: DB_ENDPOINT
5246
value: $DB_ENDPOINT
@@ -67,6 +61,7 @@ spec:
6761
secretName: db-create-users
6862
restartPolicy: Never
6963
backoffLimit: 1
64+
7065
---
7166
apiVersion: apps/v1
7267
kind: Deployment
@@ -88,7 +83,7 @@ spec:
8883
containers:
8984
- command:
9085
- sh
91-
args:
86+
args:
9287
- "-c"
9388
# long running task so the pod doesn't exit with 0
9489
- tail -f /dev/null

db-ops/job-create-db-postgres.yml.tpl

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,46 @@ apiVersion: v1
22
kind: Namespace
33
metadata:
44
name: db-ops
5+
56
---
67
apiVersion: v1
78
kind: Secret
89
metadata:
910
name: db-create-users
1011
namespace: db-ops
1112
type: Opaque
12-
stringData:
13+
stringData:
14+
RDS_MASTER_PASSWORD: $MASTER_RDS_PASSWORD
1315
create-user.sql: |
14-
REVOKE ALL PRIVILEGES ON DATABASE $DB_NAME FROM $DB_APP_USERNAME;
15-
DROP USER $DB_APP_USERNAME;
16+
SELECT 'CREATE DATABASE $DB_NAME' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '$DB_NAME');\gexec
17+
SELECT 'REVOKE ALL PRIVILEGES ON DATABASE $DB_NAME FROM $DB_APP_USERNAME;' WHERE EXISTS (SELECT FROM pg_roles WHERE rolname = '$DB_APP_USERNAME');\gexec
18+
SELECT 'DROP USER $DB_APP_USERNAME;' WHERE EXISTS (SELECT FROM pg_user WHERE usename = '$DB_APP_USERNAME');\gexec
1619
CREATE USER $DB_APP_USERNAME WITH ENCRYPTED PASSWORD '$DB_APP_PASSWORD';
1720
GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_APP_USERNAME;
18-
RDS_MASTER_PASSWORD: $MASTER_RDS_PASSWORD
21+
1922
---
2023
apiVersion: v1
2124
kind: Namespace
2225
metadata:
23-
name: $PROJECT_NAME
24-
---
25-
apiVersion: v1
26-
kind: Secret
27-
metadata:
28-
name: $PROJECT_NAME
29-
namespace: $PROJECT_NAME
30-
type: Opaque
31-
stringData:
32-
DATABASE_USERNAME: $DB_APP_USERNAME
33-
DATABASE_PASSWORD: $DB_APP_PASSWORD
26+
name: $NAMESPACE
27+
3428
---
3529
apiVersion: batch/v1
3630
kind: Job
3731
metadata:
38-
name: db-create-users-$JOB_ID
32+
name: db-create-users-$NAMESPACE-$JOB_ID
3933
namespace: db-ops
4034
spec:
4135
template:
4236
spec:
4337
containers:
4438
- name: create-rds-user
4539
image: $DOCKER_IMAGE_TAG
46-
command:
40+
command:
4741
- sh
48-
args:
49-
- '-c'
50-
- psql -U$MASTER_RDS_USERNAME -h $DB_ENDPOINT $DB_NAME -a -f/db-ops/create-user.sql > /dev/null
42+
args:
43+
- '-c'
44+
- psql -U$MASTER_RDS_USERNAME -h $DB_ENDPOINT postgres -v ON_ERROR_STOP=1 -a -f/db-ops/create-user.sql > /dev/null
5145
env:
5246
- name: PGPASSWORD
5347
valueFrom:
@@ -64,6 +58,7 @@ spec:
6458
secretName: db-create-users
6559
restartPolicy: Never
6660
backoffLimit: 1
61+
6762
---
6863
apiVersion: apps/v1
6964
kind: Deployment
@@ -85,7 +80,7 @@ spec:
8580
containers:
8681
- command:
8782
- sh
88-
args:
83+
args:
8984
- "-c"
9085
# long running task so the pod doesn't exit with 0
9186
- tail -f /dev/null

db-ops/secret-application.yml.tpl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
apiVersion: v1
3+
kind: Secret
4+
metadata:
5+
name: $PROJECT_NAME
6+
namespace: $NAMESPACE
7+
type: Opaque
8+
stringData:
9+
DATABASE_USERNAME: $DB_APP_USERNAME
10+
DATABASE_PASSWORD: $DB_APP_PASSWORD

db-ops/secret-user-auth.yml.tpl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
apiVersion: v1
3+
kind: Secret
4+
metadata:
5+
name: $PROJECT_NAME
6+
namespace: $NAMESPACE
7+
type: Opaque
8+
stringData:
9+
dsn: $DB_TYPE://$DB_APP_USERNAME:$DB_APP_PASSWORD@$DB_ENDPOINT_FOR_DSN/$DB_NAME
10+
secretsCookie: cookie-secret-$PROJECT_NAME-$SEED
11+
secretsDefault: default-secret-$PROJECT_NAME-$SEED
12+
smtpConnectionURI: http://mail-server-todo:1234

templates/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ $ curl --request POST \
9191
For Application use, see [Sendgrid resources][sendgrid-send-mail] on how to setup templates to send dynamic transactional emails. To setup emailing from your application deployment, you should create a kubernetes secret with your Sendgrid API Key(already stored in [AWS secret-manager](./terraform/bootstrap/secrets/main.tf)) in your application's namespace. Then mount the secret as an environment variable in your deployment.
9292

9393
#### Application database user creation
94-
A database user will automatically be created for a backend application with a random password, and the credentials will be stored in a kubernetes secret so they are available to the application.
94+
A database user will automatically be created for a backend application with a random password, and the credentials will be stored in a kubernetes secret in the application namespace so they are available to the application.
9595

96-
_Note: the user creation only happens once during `zero apply`. If you want to run this process again to create a new password, you can run the script `sh dp-ops/create-db-user.sh` manually, though be aware that this will cause the user and its privileges to be removed and recreated, and may disrupt your application until it is restarted.
96+
_Note: the user creation only happens once during `zero apply`. The creation happens in the script `zero-aws-eks-stack/dp-ops/create-db-user.sh`. This script should most likely not be run again as it could remove any subsequent changes to the db user or kubernetes secret._
9797

9898

9999
# Resources

templates/kubernetes/terraform/environments/prod/main.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,10 @@ module "kubernetes" {
7373
["Max C", "10.10.99.201/32", "/B3Q/Hlf+ILInjpehTLk9DZGgybdGdbm0SsG87OnWV0="],
7474
["Carter L", "10.10.99.202/32", "h2jMuaXNIlx7Z0a3owWFjPsAA8B+ZpQH3FbZK393+08="],
7575
]
76+
77+
auth_enabled = <% if eq (index .Params `userAuth`) "yes" %>true<% else %>false<% end %>
78+
auth_domain = "auth.${local.domain_name}"
79+
backend_service_domain = "<% index .Params `productionBackendSubdomain` %>${local.domain_name}"
80+
frontend_service_domain = "<% index .Params `productionFrontendSubdomain` %>${local.domain_name}"
81+
7682
}

templates/kubernetes/terraform/environments/stage/main.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,9 @@ module "kubernetes" {
7272
["Max C", "10.10.199.201/32", "/B3Q/Hlf+ILInjpehTLk9DZGgybdGdbm0SsG87OnWV0="],
7373
["Carter L", "10.10.199.202/32", "h2jMuaXNIlx7Z0a3owWFjPsAA8B+ZpQH3FbZK393+08="],
7474
]
75+
76+
auth_enabled = <% if eq (index .Params `userAuth`) "yes" %>true<% else %>false<% end %>
77+
auth_domain = "auth.${local.domain_name}"
78+
backend_service_domain = "<% index .Params `stagingBackendSubdomain` %>${local.domain_name}"
79+
frontend_service_domain = "<% index .Params `stagingFrontendSubdomain` %>${local.domain_name}"
7580
}

templates/kubernetes/terraform/modules/kubernetes/cert_manager.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
locals {
2-
cert_manager_namespace = "cert-manager"
32
cert_manager_version = "0.14.2"
43
cluster_issuer_name = var.cert_manager_use_production_acme_environment ? "clusterissuer-letsencrypt-production" : "clusterissuer-letsencrypt-staging"
54
cert_manager_acme_server = var.cert_manager_use_production_acme_environment ? "https://acme-v02.api.letsencrypt.org/directory" : "https://acme-staging-v02.api.letsencrypt.org/directory"
@@ -66,7 +65,8 @@ resource "helm_release" "cert_manager" {
6665
repository = "https://charts.jetstack.io"
6766
chart = "cert-manager"
6867
version = local.cert_manager_version
69-
namespace = local.cert_manager_namespace
68+
namespace = kubernetes_namespace.cert_manager.metadata[0].name
69+
7070
set {
7171
type = "string"
7272
name = "serviceAccount.annotations.eks\\.amazonaws\\.com/role-arn"
@@ -92,7 +92,7 @@ module "iam_assumable_role_cert_manager" {
9292
role_name = "${var.project}-k8s-${var.environment}-cert-manager"
9393
provider_url = replace(data.aws_eks_cluster.cluster.identity.0.oidc.0.issuer, "https://", "")
9494
role_policy_arns = [aws_iam_policy.cert_manager.arn]
95-
oidc_fully_qualified_subjects = ["system:serviceaccount:${local.cert_manager_namespace}:cert-manager"]
95+
oidc_fully_qualified_subjects = ["system:serviceaccount:${kubernetes_namespace.cert_manager.metadata[0].name}:cert-manager"]
9696
}
9797

9898
resource "aws_iam_policy" "cert_manager" {

0 commit comments

Comments
 (0)