integration: add cluster setup and configuration and a few tests

This commit is contained in:
Caleb Doxsey 2020-04-28 07:33:33 -06:00
parent 9860c3ce9f
commit 8fd716e1d8
24 changed files with 1689 additions and 2 deletions

View file

@ -0,0 +1,79 @@
{
apiVersion: 'v1',
kind: 'List',
items: [
{
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: {
namespace: 'default',
name: 'httpdetails',
labels: {
app: 'httpdetails',
},
},
data: {
'index.js': importstr '../../backends/httpdetails/index.js',
},
},
{
apiVersion: 'v1',
kind: 'Service',
metadata: {
namespace: 'default',
name: 'httpdetails',
labels: { app: 'httpdetails' },
},
spec: {
selector: { app: 'httpdetails' },
ports: [{
name: 'http',
port: 80,
targetPort: 'http',
}],
},
},
{
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
namespace: 'default',
name: 'httpdetails',
},
spec: {
replicas: 1,
selector: { matchLabels: { app: 'httpdetails' } },
template: {
metadata: {
labels: { app: 'httpdetails' },
},
spec: {
containers: [{
name: 'httpbin',
image: 'node:14-stretch-slim',
imagePullPolicy: 'IfNotPresent',
args: [
'node',
'/app/index.js',
],
ports: [{
name: 'http',
containerPort: 8080,
}],
volumeMounts: [{
name: 'httpdetails',
mountPath: '/app',
}],
}],
volumes: [{
name: 'httpdetails',
configMap: {
name: 'httpdetails',
},
}],
},
},
},
},
],
}

View file

@ -0,0 +1,143 @@
{
apiVersion: 'v1',
kind: 'List',
items: [
{
apiVersion: 'v1',
kind: 'Namespace',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'ingress-nginx' },
},
{
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-configuration', namespace: 'ingress-nginx' },
},
{
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'tcp-services', namespace: 'ingress-nginx' },
},
{
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'udp-services', namespace: 'ingress-nginx' },
},
{
apiVersion: 'v1',
kind: 'ServiceAccount',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-ingress-serviceaccount', namespace: 'ingress-nginx' },
},
{
apiVersion: 'rbac.authorization.k8s.io/v1beta1',
kind: 'ClusterRole',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-ingress-clusterrole' },
rules: [{ apiGroups: [''], resources: ['configmaps', 'endpoints', 'nodes', 'pods', 'secrets'], verbs: ['list', 'watch'] }, { apiGroups: [''], resources: ['nodes'], verbs: ['get'] }, { apiGroups: [''], resources: ['services'], verbs: ['get', 'list', 'watch'] }, { apiGroups: [''], resources: ['events'], verbs: ['create', 'patch'] }, { apiGroups: ['extensions', 'networking.k8s.io'], resources: ['ingresses'], verbs: ['get', 'list', 'watch'] }, { apiGroups: ['extensions', 'networking.k8s.io'], resources: ['ingresses/status'], verbs: ['update'] }],
},
{
apiVersion: 'rbac.authorization.k8s.io/v1beta1',
kind: 'Role',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-ingress-role', namespace: 'ingress-nginx' },
rules: [{ apiGroups: [''], resources: ['configmaps', 'pods', 'secrets', 'namespaces'], verbs: ['get'] }, { apiGroups: [''], resourceNames: ['ingress-controller-leader-nginx'], resources: ['configmaps'], verbs: ['get', 'update'] }, { apiGroups: [''], resources: ['configmaps'], verbs: ['create'] }, { apiGroups: [''], resources: ['endpoints'], verbs: ['get'] }],
},
{
apiVersion: 'rbac.authorization.k8s.io/v1beta1',
kind: 'RoleBinding',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-ingress-role-nisa-binding', namespace: 'ingress-nginx' },
roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'Role', name: 'nginx-ingress-role' },
subjects: [{ kind: 'ServiceAccount', name: 'nginx-ingress-serviceaccount', namespace: 'ingress-nginx' }],
},
{
apiVersion: 'rbac.authorization.k8s.io/v1beta1',
kind: 'ClusterRoleBinding',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-ingress-clusterrole-nisa-binding' },
roleRef: { apiGroup: 'rbac.authorization.k8s.io', kind: 'ClusterRole', name: 'nginx-ingress-clusterrole' },
subjects: [{ kind: 'ServiceAccount', name: 'nginx-ingress-serviceaccount', namespace: 'ingress-nginx' }],
},
{
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'nginx-ingress-controller', namespace: 'ingress-nginx' },
spec: {
replicas: 1,
selector: { matchLabels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' } },
template: {
metadata: { annotations: { 'prometheus.io/port': '10254', 'prometheus.io/scrape': 'true' }, labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' } },
spec: {
containers: [{
name: 'nginx-ingress-controller',
image: 'quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.30.0',
args: [
'/nginx-ingress-controller',
'--configmap=$(POD_NAMESPACE)/nginx-configuration',
'--tcp-services-configmap=$(POD_NAMESPACE)/tcp-services',
'--udp-services-configmap=$(POD_NAMESPACE)/udp-services',
'--publish-service=$(POD_NAMESPACE)/ingress-nginx',
'--annotations-prefix=nginx.ingress.kubernetes.io',
'--v=2',
],
env: [
{ name: 'POD_NAME', valueFrom: { fieldRef: { fieldPath: 'metadata.name' } } },
{ name: 'POD_NAMESPACE', valueFrom: { fieldRef: { fieldPath: 'metadata.namespace' } } },
],
lifecycle: { preStop: { exec: { command: ['/wait-shutdown'] } } },
livenessProbe: { failureThreshold: 3, httpGet: { path: '/healthz', port: 10254, scheme: 'HTTP' }, initialDelaySeconds: 10, periodSeconds: 10, successThreshold: 1, timeoutSeconds: 10 },
ports: [{ containerPort: 80, name: 'http', protocol: 'TCP' }, { containerPort: 443, name: 'https', protocol: 'TCP' }],
readinessProbe: { failureThreshold: 3, httpGet: { path: '/healthz', port: 10254, scheme: 'HTTP' }, periodSeconds: 10, successThreshold: 1, timeoutSeconds: 10 },
securityContext: { allowPrivilegeEscalation: true, capabilities: { add: ['NET_BIND_SERVICE'], drop: ['ALL'] }, runAsUser: 101 },
}],
nodeSelector: { 'kubernetes.io/os': 'linux' },
serviceAccountName: 'nginx-ingress-serviceaccount',
terminationGracePeriodSeconds: 300,
},
},
},
},
{
apiVersion: 'v1',
kind: 'LimitRange',
metadata: { labels: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' }, name: 'ingress-nginx', namespace: 'ingress-nginx' },
spec: { limits: [{ min: { cpu: '100m', memory: '90Mi' }, type: 'Container' }] },
},
{
apiVersion: 'v1',
kind: 'Service',
metadata: {
namespace: 'ingress-nginx',
name: 'ingress-nginx',
labels: {
'app.kubernetes.io/name': 'ingress-nginx',
'app.kubernetes.io/part-of': 'ingress-nginx',
},
},
spec: {
type: 'ClusterIP',
clusterIP: '10.96.1.1',
selector: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' },
ports: [
{ name: 'http', port: 80, protocol: 'TCP', targetPort: 'http' },
{ name: 'https', port: 443, protocol: 'TCP', targetPort: 'https' },
],
},
},
{
apiVersion: 'v1',
kind: 'Service',
metadata: {
namespace: 'ingress-nginx',
name: 'ingress-nginx-nodeport',
labels: {
'app.kubernetes.io/name': 'ingress-nginx',
'app.kubernetes.io/part-of': 'ingress-nginx',
},
},
spec: {
type: 'NodePort',
selector: { 'app.kubernetes.io/name': 'ingress-nginx', 'app.kubernetes.io/part-of': 'ingress-nginx' },
ports: [
{ name: 'http', port: 80, protocol: 'TCP', targetPort: 'http', nodePort: 30080 },
{ name: 'https', port: 443, protocol: 'TCP', targetPort: 'https', nodePort: 30443 },
],
},
},
],
}

View file

@ -0,0 +1,337 @@
local tls = import './tls.libsonnet';
local PomeriumPolicy = function() [
{
from: 'http://httpdetails.localhost.pomerium.io',
prefix: '/by-domain',
to: 'http://httpdetails.default.svc.cluster.local',
allowed_domains: ['dogs.test'],
},
{
from: 'http://httpdetails.localhost.pomerium.io',
prefix: '/by-user',
to: 'http://httpdetails.default.svc.cluster.local',
allowed_users: ['bob@dogs.test'],
},
{
from: 'http://httpdetails.localhost.pomerium.io',
prefix: '/by-group',
to: 'http://httpdetails.default.svc.cluster.local',
allowed_groups: ['admin'],
},
{
from: 'http://httpdetails.localhost.pomerium.io',
to: 'http://httpdetails.default.svc.cluster.local',
allow_public_unauthenticated_access: true,
},
];
local PomeriumPolicyHash = std.base64(std.md5(std.manifestJsonEx(PomeriumPolicy(), '')));
local PomeriumTLSSecret = function() {
apiVersion: 'v1',
kind: 'Secret',
type: 'kubernetes.io/tls',
metadata: {
namespace: 'default',
name: 'pomerium-tls',
},
data: {
'tls.crt': std.base64(tls.cert),
'tls.key': std.base64(tls.key),
},
};
local PomeriumCAsConfigMap = function() {
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: {
namespace: 'default',
name: 'pomerium-cas',
labels: {
'app.kubernetes.io/part-of': 'pomerium',
},
},
data: {
'pomerium.crt': tls.ca,
},
};
local PomeriumConfigMap = function() {
apiVersion: 'v1',
kind: 'ConfigMap',
metadata: {
namespace: 'default',
name: 'pomerium',
labels: {
'app.kubernetes.io/part-of': 'pomerium',
},
},
data: {
ADDRESS: ':443',
GRPC_ADDRESS: ':5080',
GRPC_INSECURE: 'true',
DEBUG: 'true',
LOG_LEVEL: 'debug',
AUTHENTICATE_SERVICE_URL: 'https://authenticate.localhost.pomerium.io',
AUTHENTICATE_CALLBACK_PATH: '/oauth2/callback',
AUTHORIZE_SERVICE_URL: 'http://authorize.default.svc.cluster.local:5080',
CACHE_SERVICE_URL: 'http://cache.default.svc.cluster.local:5080',
FORWARD_AUTH_URL: 'https://forward-authenticate.localhost.pomerium.io',
SHARED_SECRET: 'Wy+c0uSuIM0yGGXs82MBwTZwRiZ7Ki2T0LANnmzUtkI=',
COOKIE_SECRET: 'eZ91a/j9fhgki9zPDU5zHdQWX4io89pJanChMVa5OoM=',
CERTIFICATE: std.base64(tls.cert),
CERTIFICATE_KEY: std.base64(tls.key),
IDP_PROVIDER: 'oidc',
IDP_PROVIDER_URL: 'https://openid.localhost.pomerium.io',
IDP_CLIENT_ID: 'pomerium-authenticate',
IDP_CLIENT_SECRET: 'pomerium-authenticate-secret',
POLICY: std.base64(std.manifestYamlDoc(PomeriumPolicy())),
},
};
local PomeriumDeployment = function(svc) {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
namespace: 'default',
name: 'pomerium-' + svc,
labels: {
app: 'pomerium-' + svc,
'app.kubernetes.io/part-of': 'pomerium',
},
},
spec: {
replicas: 1,
selector: {
matchLabels: {
app: 'pomerium-' + svc,
},
},
template: {
metadata: {
labels: {
app: 'pomerium-' + svc,
'app.kubernetes.io/part-of': 'pomerium',
},
annotations: {
'policy-version': PomeriumPolicyHash,
},
},
spec: {
hostAliases: [{
ip: '10.96.1.1',
hostnames: [
'openid.localhost.pomerium.io',
],
}],
initContainers: [{
name: 'pomerium-' + svc + '-certs',
image: 'buildpack-deps:buster-curl',
imagePullPolicy: 'Always',
command: ['sh', '-c', |||
cp /incoming-certs/* /usr/local/share/ca-certificates
update-ca-certificates
|||],
volumeMounts: [
{
name: 'incoming-certs',
mountPath: '/incoming-certs',
},
{
name: 'outgoing-certs',
mountPath: '/etc/ssl/certs',
},
],
}],
containers: [{
name: 'pomerium-' + svc,
image: 'pomerium/pomerium:dev',
imagePullPolicy: 'IfNotPresent',
envFrom: [{
configMapRef: { name: 'pomerium' },
}],
env: [{
name: 'SERVICES',
value: svc,
}],
ports: [
{ name: 'https', containerPort: 443 },
{ name: 'grpc', containerPort: 5080 },
],
volumeMounts: [
{
name: 'outgoing-certs',
mountPath: '/etc/ssl/certs',
},
],
}],
volumes: [
{
name: 'incoming-certs',
configMap: {
name: 'pomerium-cas',
},
},
{
name: 'outgoing-certs',
emptyDir: {},
},
],
},
},
},
};
local PomeriumService = function(svc) {
apiVersion: 'v1',
kind: 'Service',
metadata: {
namespace: 'default',
name: svc,
labels: {
app: 'pomerium-' + svc,
'app.kubernetes.io/part-of': 'pomerium',
},
},
spec: {
ports: [
{
name: 'https',
port: 443,
targetPort: 'https',
},
{
name: 'grpc',
port: 5080,
targetPort: 'grpc',
},
],
selector: {
app: 'pomerium-' + svc,
},
},
};
local PomeriumIngress = function() {
local proxyHosts = [
'forward-authenticate.localhost.pomerium.io',
'httpecho.localhost.pomerium.io',
'httpdetails.localhost.pomerium.io',
],
apiVersion: 'extensions/v1beta1',
kind: 'Ingress',
metadata: {
namespace: 'default',
name: 'pomerium',
annotations: {
'kubernetes.io/ingress.class': 'nginx',
'nginx.ingress.kubernetes.io/backend-protocol': 'HTTPS',
'nginx.ingress.kubernetes.io/proxy-buffer-size': '16k',
},
},
spec: {
tls: [
{
hosts: [
'authenticate.localhost.pomerium.io',
] + proxyHosts,
secretName: 'pomerium-tls',
},
],
rules: [
{
host: 'authenticate.localhost.pomerium.io',
http: {
paths: [
{
path: '/',
backend: {
serviceName: 'authenticate',
servicePort: 'https',
},
},
],
},
},
] + [{
host: host,
http: {
paths: [{
path: '/',
backend: {
serviceName: 'proxy',
servicePort: 'https',
},
}],
},
} for host in proxyHosts],
},
};
local PomeriumForwardAuthIngress = function() {
apiVersion: 'extensions/v1beta1',
kind: 'Ingress',
metadata: {
namespace: 'default',
name: 'pomerium-fa',
annotations: {
'kubernetes.io/ingress.class': 'nginx',
'nginx.ingress.kubernetes.io/auth-url': 'https://forward-authenticate.localhost.pomerium.io/verify?uri=$scheme://$host$request_uri',
'nginx.ingress.kubernetes.io/auth-signin': 'https://forward-authenticate.localhost.pomerium.io/?uri=$scheme://$host$request_uri',
'nginx.ingress.kubernetes.io/proxy-buffer-size': '16k',
},
},
spec: {
tls: [
{
hosts: [
'fa-httpecho.localhost.pomerium.io',
],
secretName: 'pomerium-tls',
},
],
rules: [
{
host: 'fa-httpecho.localhost.pomerium.io',
http: {
paths: [
{
path: '/',
backend: {
serviceName: 'httpecho',
servicePort: 'http',
},
},
],
},
},
],
},
};
{
apiVersion: 'v1',
kind: 'List',
items: [
PomeriumConfigMap(),
PomeriumCAsConfigMap(),
PomeriumTLSSecret(),
PomeriumService('authenticate'),
PomeriumDeployment('authenticate'),
PomeriumService('authorize'),
PomeriumDeployment('authorize'),
PomeriumService('cache'),
PomeriumDeployment('cache'),
PomeriumService('proxy'),
PomeriumDeployment('proxy'),
PomeriumIngress(),
PomeriumForwardAuthIngress(),
],
}

View file

@ -0,0 +1,106 @@
local Service = function() {
apiVersion: 'v1',
kind: 'Service',
metadata: {
namespace: 'default',
name: 'openid',
labels: {
app: 'openid',
'app.kubernetes.io/part-of': 'openid',
},
},
spec: {
selector: { app: 'openid' },
ports: [
{
name: 'http',
port: 80,
targetPort: 'http',
},
],
},
};
local Deployment = function() {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
namespace: 'default',
name: 'openid',
labels: {
app: 'openid',
'app.kubernetes.io/part-of': 'openid',
},
},
spec: {
replicas: 1,
selector: { matchLabels: { app: 'openid' } },
template: {
metadata: {
labels: {
app: 'openid',
'app.kubernetes.io/part-of': 'openid',
},
},
spec: {
containers: [{
name: 'openid',
image: 'quay.io/calebdoxsey/reference-openid-provider:latest',
imagePullPolicy: 'IfNotPresent',
ports: [
{ name: 'http', containerPort: 6080 },
],
}],
},
},
},
};
local Ingress = function() {
apiVersion: 'extensions/v1beta1',
kind: 'Ingress',
metadata: {
namespace: 'default',
name: 'openid',
annotations: {
'kubernetes.io/ingress.class': 'nginx',
'nginx.ingress.kubernetes.io/backend-protocol': 'HTTP',
},
},
spec: {
tls: [
{
hosts: [
'openid.localhost.pomerium.io',
],
secretName: 'pomerium-tls',
},
],
rules: [
{
host: 'openid.localhost.pomerium.io',
http: {
paths: [
{
path: '/',
backend: {
serviceName: 'openid',
servicePort: 'http',
},
},
],
},
},
],
},
};
{
apiVersion: 'v1',
kind: 'List',
items: [
Service(),
Deployment(),
Ingress(),
],
}

View file

@ -0,0 +1,5 @@
{
cert: std.extVar('tls-cert'),
key: std.extVar('tls-key'),
ca: std.extVar('tls-ca'),
}