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

Add OIDC policy #1304

Merged
merged 11 commits into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 7 additions & 3 deletions build/DockerfileForPlus
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ FROM debian:buster-slim AS base
LABEL maintainer="NGINX Docker Maintainers <[email protected]>"

ENV NGINX_PLUS_VERSION 23-1~buster
ENV NGINX_NJS_VERSION 23+0.5.0-1~buster
ARG IC_VERSION

# Download certificate and key from the customer portal (https://cs.nginx.com)
Expand Down Expand Up @@ -36,7 +37,7 @@ RUN --mount=type=secret,id=nginx-repo.crt \
&& echo "Acquire::https::plus-pkgs.nginx.com::SslKey \"/etc/ssl/nginx/nginx-repo.key\";" >> /etc/apt/apt.conf.d/90nginx \
&& echo "Acquire::https::plus-pkgs.nginx.com::User-Agent \"k8s-ic-$IC_VERSION-apt\";" >> /etc/apt/apt.conf.d/90nginx \
&& printf "deb https://plus-pkgs.nginx.com/debian buster nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
&& apt-get update && apt-get install -y nginx-plus=${NGINX_PLUS_VERSION} \
&& apt-get update && apt-get install -y nginx-plus=${NGINX_PLUS_VERSION} nginx-plus-module-njs=${NGINX_NJS_VERSION} \
&& setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx \
'cap_net_bind_service=+ep' /usr/sbin/nginx-debug \
&& apt-get remove --purge --auto-remove -y gnupg1 \
Expand All @@ -54,9 +55,10 @@ RUN ln -sf /proc/1/fd/1 /var/log/nginx/access.log \
RUN mkdir -p /var/lib/nginx \
/etc/nginx/secrets \
/etc/nginx/stream-conf.d \
/etc/nginx/oidc \
&& chown -R nginx:0 /etc/nginx \
/var/cache/nginx \
/var/lib/nginx/ \
/var/cache/nginx \
/var/lib/nginx/ \
&& apt-get remove --purge -y libcap2-bin \
&& rm /etc/nginx/conf.d/*

Expand All @@ -67,6 +69,8 @@ COPY internal/configs/version1/nginx-plus.ingress.tmpl \
internal/configs/version2/nginx-plus.virtualserver.tmpl \
internal/configs/version2/nginx-plus.transportserver.tmpl /

COPY internal/configs/oidc/* /etc/nginx/oidc/

# Uncomment the line below if you would like to add the default.pem to the image
# and use it as a certificate and key for the default server
# ADD default.pem /etc/nginx/secrets/default
Expand Down
10 changes: 7 additions & 3 deletions build/DockerfileWithOpentracingForPlus
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ FROM debian:buster-slim AS base
LABEL maintainer="NGINX Docker Maintainers <[email protected]>"

ENV NGINX_PLUS_VERSION 23-1~buster
ENV NGINX_NJS_VERSION 23+0.5.0-1~buster
ENV NGINX_OPENTRACING_MODULE_VERSION 23+0.9.0-1~buster

ARG IC_VERSION
Expand Down Expand Up @@ -47,7 +48,7 @@ RUN --mount=type=secret,id=nginx-repo.crt \
&& echo "Acquire::https::plus-pkgs.nginx.com::User-Agent \"k8s-ic-$IC_VERSION-apt\";" >> /etc/apt/apt.conf.d/90nginx \
&& printf "deb https://plus-pkgs.nginx.com/debian buster nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
&& apt-get update && apt-get install -y \
nginx-plus=${NGINX_PLUS_VERSION} \
nginx-plus=${NGINX_PLUS_VERSION} nginx-plus-module-njs=${NGINX_NJS_VERSION} \
# Install OpenTracing module
nginx-plus-module-opentracing=${NGINX_OPENTRACING_MODULE_VERSION} \
&& setcap 'cap_net_bind_service=+ep' /usr/sbin/nginx \
Expand All @@ -70,9 +71,10 @@ COPY --from=tracer-downloader /usr/local/lib/libjaegertracing_plugin.so /usr/loc
RUN mkdir -p /var/lib/nginx \
/etc/nginx/secrets \
/etc/nginx/stream-conf.d \
/etc/nginx/oidc \
&& chown -R nginx:0 /etc/nginx \
/var/cache/nginx \
/var/lib/nginx/ \
/var/cache/nginx \
/var/lib/nginx/ \
&& apt-get remove --purge -y libcap2-bin \
&& rm /etc/nginx/conf.d/*

Expand All @@ -83,6 +85,8 @@ COPY internal/configs/version1/nginx-plus.ingress.tmpl \
internal/configs/version2/nginx-plus.virtualserver.tmpl \
internal/configs/version2/nginx-plus.transportserver.tmpl /

COPY internal/configs/oidc/* /etc/nginx/oidc/

# Uncomment the line below if you would like to add the default.pem to the image
# and use it as a certificate and key for the default server
# ADD default.pem /etc/nginx/secrets/default
Expand Down
8 changes: 6 additions & 2 deletions build/appprotect/DockerfileWithAppProtectForPlus
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ENV APPPROTECT_SIG_VERSION 2020.12.30-1~buster
ENV APPPROTECT_THREAT_CAMPAIGNS_VERSION 2021.01.03-1~buster
ENV NGINX_PLUS_VERSION 23-1~buster
ENV NGINX_PLUS_RELEASE R23
ENV NGINX_NJS_VERSION 23+0.5.0-1~buster
ARG IC_VERSION

# Download certificate and key from the customer portal (https://cs.nginx.com)
Expand Down Expand Up @@ -49,7 +50,7 @@ RUN --mount=type=secret,id=nginx-repo.crt \
&& echo "Acquire::https::app-protect-sigs.nginx.com::Verify-Host \"true\";" >> /etc/apt/apt.conf.d/90app-protect-sigs \
&& echo "Acquire::https::app-protect-sigs.nginx.com::SslCert \"/etc/ssl/nginx/nginx-repo.crt\";" >> /etc/apt/apt.conf.d/90app-protect-sigs \
&& echo "Acquire::https::app-protect-sigs.nginx.com::SslKey \"/etc/ssl/nginx/nginx-repo.key\";" >> /etc/apt/apt.conf.d/90app-protect-sigs \
&& apt-get update && apt-get install -y nginx-plus=$NGINX_PLUS_VERSION \
&& apt-get update && apt-get install -y nginx-plus=$NGINX_PLUS_VERSION nginx-plus-module-njs=${NGINX_NJS_VERSION} \
nginx-plus-module-appprotect=$APPPROTECT_MODULE_VERSION \
app-protect-plugin=$APPPROTECT_PLUGIN_VERSION \
app-protect-engine=$APPPROTECT_ENGINE_VERSION \
Expand Down Expand Up @@ -83,6 +84,7 @@ RUN mkdir -p /var/lib/nginx \
/etc/nginx/waf/nac-usersigs \
/var/log/app_protect \
/opt/app_protect \
/etc/nginx/oidc \
&& touch /etc/nginx/waf/nac-usersigs/index.conf \
&& chown -R nginx:0 /etc/app_protect \
/usr/share/ts \
Expand All @@ -106,7 +108,7 @@ RUN printf "MODULE = ALL;\nLOG_LEVEL = TS_CRIT;\nFILE = 2;\n" > /etc/app_protect
; do sed -i "/\[$v/a log_level=fatal" "/etc/app_protect/tools/asm_logging.conf" \
; done

COPY --chown=nginx:0 build/appprotect/log-default.json /etc/nginx
COPY --chown=nginx:0 build/appprotect/log-default.json /etc/nginx

EXPOSE 80 443

Expand All @@ -115,6 +117,8 @@ COPY internal/configs/version1/nginx-plus.ingress.tmpl \
internal/configs/version2/nginx-plus.virtualserver.tmpl \
internal/configs/version2/nginx-plus.transportserver.tmpl /

COPY internal/configs/oidc/* /etc/nginx/oidc/

# Uncomment the line below if you would like to add the default.pem to the image
# and use it as a certificate and key for the default server
# ADD default.pem /etc/nginx/secrets/default
Expand Down
13 changes: 8 additions & 5 deletions cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ var (
- i.e have the annotation "kubernetes.io/ingress.class" equal to the class.
Additionally, the Ingress Controller processes resources that do not have the class set,
which can be disabled by setting the "-use-ingress-class-only" flag

The Ingress Controller processes all the VirtualServer/VirtualServerRoute resources that do not have the "ingressClassName" field for all versions of kubernetes.`)

useIngressClassOnly = flag.Bool("use-ingress-class-only", false,
Expand Down Expand Up @@ -112,7 +112,7 @@ var (
(default for NGINX "nginx.transportserver.tmpl"; default for NGINX Plus "nginx-plus.transportserver.tmpl")`)

externalService = flag.String("external-service", "",
`Specifies the name of the service with the type LoadBalancer through which the Ingress controller pods are exposed externally.
`Specifies the name of the service with the type LoadBalancer through which the Ingress controller pods are exposed externally.
The external address of the service is used when reporting the status of Ingress, VirtualServer and VirtualServerRoute resources. For Ingress resources only: Requires -report-ingress-status.`)

nginxCisConnector = flag.String("nginx-cis-connector", "",
Expand Down Expand Up @@ -165,7 +165,7 @@ var (

globalConfiguration = flag.String("global-configuration", "",
`A GlobalConfiguration resource for global configuration of the Ingress Controller. Requires -enable-custom-resources. If the flag is set,
but the Ingress controller is not able to fetch the corresponding resource from Kubernetes API, the Ingress Controller
but the Ingress controller is not able to fetch the corresponding resource from Kubernetes API, the Ingress Controller
will fail to start. Format: <namespace>/<name>`)

enableTLSPassthrough = flag.Bool("enable-tls-passthrough", false,
Expand Down Expand Up @@ -521,6 +521,7 @@ func main() {
NginxServiceMesh: *spireAgentAddress != "",
MainAppProtectLoadModule: *appProtect,
EnableLatencyMetrics: *enableLatencyMetrics,
EnablePreviewPolicies: *enablePreviewPolicies,
}

ngxConfig := configs.GenerateNginxMainConfig(staticCfgParams, cfgParams)
Expand Down Expand Up @@ -790,8 +791,10 @@ func getAndValidateSecret(kubeClient *kubernetes.Clientset, secretNsName string)
return secret, nil
}

const locationFmt = `/[^\s{};]*`
const locationErrMsg = "must start with / and must not include any whitespace character, `{`, `}` or `;`"
const (
locationFmt = `/[^\s{};]*`
locationErrMsg = "must start with / and must not include any whitespace character, `{`, `}` or `;`"
)

var locationRegexp = regexp.MustCompile("^" + locationFmt + "$")

Expand Down
18 changes: 18 additions & 0 deletions deployments/common/crds-v1beta1/k8s.nginx.org_policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ spec:
type: string
token:
type: string
oidc:
description: OIDC defines an Open ID Connect policy.
type: object
properties:
authEndpoint:
type: string
clientID:
type: string
clientSecret:
type: string
jwksURI:
type: string
redirectURI:
type: string
scope:
type: string
tokenEndpoint:
type: string
rateLimit:
description: 'RateLimit defines a rate limit policy. policy status: preview'
type: object
Expand Down
18 changes: 18 additions & 0 deletions deployments/common/crds/k8s.nginx.org_policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,24 @@ spec:
type: string
token:
type: string
oidc:
description: OIDC defines an Open ID Connect policy.
type: object
properties:
authEndpoint:
type: string
clientID:
type: string
clientSecret:
type: string
jwksURI:
type: string
redirectURI:
type: string
scope:
type: string
tokenEndpoint:
type: string
rateLimit:
description: 'RateLimit defines a rate limit policy. policy status: preview'
type: object
Expand Down
18 changes: 18 additions & 0 deletions deployments/helm-chart/crds/k8s.nginx.org_policies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ spec:
type: string
token:
type: string
oidc:
description: OIDC defines an Open ID Connect policy.
type: object
properties:
authEndpoint:
type: string
clientID:
type: string
clientSecret:
type: string
jwksURI:
type: string
redirectURI:
type: string
scope:
type: string
tokenEndpoint:
type: string
rateLimit:
description: 'RateLimit defines a rate limit policy. policy status: preview'
type: object
Expand Down
88 changes: 88 additions & 0 deletions examples-of-custom-resources/oidc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# OIDC

In this example, we deploy keycloak and a web application configure load balancing for it via a VirtualServer, and apply an OpenID Connect policy.

## Prerequisites

1. Follow the [installation](https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/) instructions to deploy the Ingress Controller.
1. Save the public IP address of the Ingress Controller into a shell variable:
```
$ IC_IP=XXX.YYY.ZZZ.III
```
1. Save the HTTP port of the Ingress Controller into a shell variable:
```
$ IC_HTTPS_PORT=<port number>
```

## Step 1 - Deploy a Web Application

Create the application deployment and service:
```
$ kubectl apply -f webapp.yaml
```

## Step 2 - Deploy Keycloak

Create keycloak deployment and service:
```
$ kubectl apply -f keycloak.yaml
```

To set up Keycloak, you can either follow the steps in the "Configuring Keycloak" section of the documentation [here](https://docs.nginx.com/nginx/deployment-guides/single-sign-on/keycloak/#configuring-keycloak) or execute the commands [here](./keycloak_setup.md).


## Step 3 - Deploy the Client Secret

1. Edit `client-secret.yaml` with your secret.

1. Create a secret with the name `oidc-secret` that will be used for OIDC validation:
```
$ kubectl apply -f client-secret.yaml
```

## Step 4 - Deploy the OIDC Policy

1. Modify the URL `authEndpoint` in `oidc.yaml` with the public IP address or DNS of keycloak.

1. Create a policy with the name `oidc-policy` that references the secret from the previous step:
```
$ kubectl apply -f oidc.yaml
```

## Step 5 - Deploy the Service for the Ingress Controller and update ConfigMap
1. Deploy the service.
```
$ kubectl apply -f service/nodeport.yaml
```
1. Update the ConfigMap with the config required for OIDC.
```
data:
stream-snippets: |
resolver 10.96.0.10 valid=5s;
server {
listen 12345;
zone_sync;
zone_sync_server nginx-ic-svc.nginx-ingress.svc.cluster.local:12345 resolve;
}
```
1. Apply the ConfigMap.
```
$ kubectl apply -f common/nginx-config.yaml
```

## Step 6 - Configure Load Balancing and TLS Termination
1. Create the secret with the TLS certificate and key:
```
$ kubectl create -f tls-secret.yaml
```

2. Create a VirtualServer resource for the web application:
```
$ kubectl apply -f virtual-server.yaml
```

Note that the VirtualServer references the policy `oidc-policy` created in Step 4.

## Step 5 - Test the Configuration

Open a web browser and navigate to the URL of the Ingress Controller
7 changes: 7 additions & 0 deletions examples-of-custom-resources/oidc/client-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: oidc-secret
type: nginx.org/oidc
data:
client-secret: c3VwZXItc2VjcmV0IQo
51 changes: 51 additions & 0 deletions examples-of-custom-resources/oidc/keycloak.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
apiVersion: v1
kind: Service
metadata:
name: keycloak
labels:
app: keycloak
spec:
ports:
- name: http
port: 8080
targetPort: 8080
selector:
app: keycloak
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
namespace: default
labels:
app: keycloak
spec:
replicas: 1
selector:
matchLabels:
app: keycloak
template:
metadata:
labels:
app: keycloak
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:12.0.1
env:
- name: KEYCLOAK_USER
value: "admin"
- name: KEYCLOAK_PASSWORD
value: "admin"
- name: PROXY_ADDRESS_FORWARDING
value: "true"
ports:
- name: http
containerPort: 8080
- name: https
containerPort: 8443
readinessProbe:
httpGet:
path: /auth/realms/master
port: 8080
Loading