-
-
Notifications
You must be signed in to change notification settings - Fork 64
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
NGINX Identity Aware Proxy #202
base: master
Are you sure you want to change the base?
Changes from all commits
d89265b
01c5305
e312b8a
ac3939d
bde8e3e
09ace7a
edcba8a
add0236
8fe117b
a1028b4
c0e8e44
3c5945e
c0138bc
fa859d3
027d049
a38f424
86b9622
18f53e5
12dcf8d
d7c8453
cc48145
4d33eb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Patterns to ignore when building packages. | ||
# This supports shell glob matching, relative path matching, and | ||
# negation (prefixed with !). Only one pattern per line. | ||
.DS_Store | ||
# Common VCS dirs | ||
.git/ | ||
.gitignore | ||
.bzr/ | ||
.bzrignore | ||
.hg/ | ||
.hgignore | ||
.svn/ | ||
# Common backup files | ||
*.swp | ||
*.bak | ||
*.tmp | ||
*~ | ||
# Various IDEs | ||
.project | ||
.idea/ | ||
*.tmproj |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
apiVersion: v1 | ||
description: A Helm chart for Kubernetes | ||
name: nginx-iap | ||
version: 0.0.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
kind: Pod | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are the files in |
||
apiVersion: v1 | ||
metadata: | ||
namespace: pr123 | ||
name: apple-app | ||
labels: | ||
app: apple | ||
spec: | ||
containers: | ||
- name: apple-app | ||
image: hashicorp/http-echo | ||
args: | ||
- "-text=apple" | ||
--- | ||
|
||
kind: Service | ||
apiVersion: v1 | ||
metadata: | ||
namespace: pr123 | ||
name: apple | ||
spec: | ||
selector: | ||
app: apple | ||
ports: | ||
- port: 80 | ||
targetPort: 5678 # Default port for image |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
kind: Pod | ||
apiVersion: v1 | ||
metadata: | ||
namespace: pr123 | ||
name: banana-app | ||
labels: | ||
app: banana | ||
spec: | ||
containers: | ||
- name: banana-app | ||
image: hashicorp/http-echo | ||
args: | ||
- "-text=banana" | ||
|
||
--- | ||
|
||
kind: Service | ||
apiVersion: v1 | ||
metadata: | ||
namespace: pr123 | ||
name: banana | ||
spec: | ||
selector: | ||
app: banana | ||
ports: | ||
- port: 80 | ||
targetPort: 5678 # Default port for image |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
apiVersion: extensions/v1beta1 | ||
kind: Deployment | ||
metadata: | ||
name: echoserver | ||
namespace: pr123 | ||
spec: | ||
replicas: 1 | ||
template: | ||
metadata: | ||
labels: | ||
app: echoserver | ||
spec: | ||
containers: | ||
- image: gcr.io/google_containers/echoserver:1.4 | ||
imagePullPolicy: Always | ||
name: echoserver | ||
ports: | ||
- containerPort: 8080 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
apiVersion: v1 | ||
kind: Namespace | ||
metadata: | ||
name: pr123 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
name: echoserver | ||
namespace: pr123 | ||
spec: | ||
ports: | ||
- port: 80 | ||
targetPort: 8080 | ||
protocol: TCP | ||
type: NodePort | ||
selector: | ||
app: echoserver |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
1. Get the application URL by running these commands: | ||
{{- if contains "NodePort" .Values.oauth.service.type }} | ||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}) | ||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") | ||
echo http://$NODE_IP:$NODE_PORT/login | ||
{{- else if contains "LoadBalancer" .Values.oauth.service.type }} | ||
NOTE: It may take a few minutes for the LoadBalancer IP to be available. | ||
You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' | ||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') | ||
echo http://$SERVICE_IP:{{ .Values.oauth.service.externalPort }} | ||
{{- else if contains "ClusterIP" .Values.oauth.service.type }} | ||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "fullname" . }}" -o jsonpath="{.items[0].metadata.name}") | ||
echo "Visit http://127.0.0.1:8080 to use your application" | ||
kubectl port-forward $POD_NAME 8080:{{ .Values.oauth.service.externalPort }} | ||
{{- end }} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,40 @@ | ||||||
{{/* vim: set filetype=mustache: */}} | ||||||
{{/* | ||||||
Expand the name of the chart. | ||||||
*/}} | ||||||
{{- define "name" -}} | ||||||
{{- default .Chart.Name .Values.nameOverride | trunc 24 | trimSuffix "-" -}} | ||||||
{{- end -}} | ||||||
|
||||||
{{/* | ||||||
Create a default fully qualified app name. | ||||||
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||||||
*/}} | ||||||
{{- define "fullname" -}} | ||||||
{{- $name := default .Chart.Name .Values.nameOverride -}} | ||||||
{{- printf "%s-%s" .Release.Name $name | trunc 24 | trimSuffix "-" -}} | ||||||
{{- end -}} | ||||||
|
||||||
{{/* | ||||||
Create a default fully qualified oauth name. | ||||||
We limit this value to 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no |
||||||
*/}} | ||||||
{{- define "fullname_oauth" -}} | ||||||
{{- printf "%.17s-oauth" .Release.Name | trimSuffix "-" -}} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is |
||||||
{{- end -}} | ||||||
|
||||||
{{/* | ||||||
Create a default fully qualified proxy name. | ||||||
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no |
||||||
*/}} | ||||||
{{- define "fullname_proxy" -}} | ||||||
{{- printf "%.17s-proxy" .Release.Name | trimSuffix "-" -}} | ||||||
{{- end -}} | ||||||
|
||||||
{{/* | ||||||
Create a default fully qualified proxy name. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no |
||||||
*/}} | ||||||
{{- define "fullname_ingress" -}} | ||||||
{{- printf "%.16s-ingress" .Release.Name | trimSuffix "-" -}} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is |
||||||
{{- end -}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
apiVersion: v1 | ||
kind: ConfigMap | ||
metadata: | ||
name: {{ template "fullname_proxy" . }} | ||
labels: | ||
app: {{ template "fullname" . }} | ||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" | ||
release: "{{ .Release.Name }}" | ||
heritage: "{{ .Release.Service }}" | ||
data: | ||
default.conf: |- | ||
# nginx requires a 'resolver' directive when variables appear in proxy_pass arguments | ||
# (eg: proxy_pass "http://$service.$pr_number..." ) | ||
resolver {{ .Values.kube_dns_hostname }} ipv6=off; | ||
|
||
upstream localhost_oauth2_proxy { | ||
least_conn; | ||
server 127.0.0.1:81; | ||
} | ||
|
||
server { | ||
listen 80; | ||
|
||
# TODO(mtamsky): It might be clearer if we had two server{} | ||
# blocks, each with unique server_name patterns. This would | ||
# create a clear separation of the iap from internal services. | ||
|
||
# Currently, this server{} config answers for both: | ||
# iap.DOMAIN | ||
server_name {{ .Values.iap_hostname }}.{{ .Values.DNS_ZONE }}; | ||
# pr123-service.DOMAIN | ||
server_name ~^(?<pr_number>[Pp][Rr][0-9]+)-(?<service>[^.]+)\.{{ .Values.iap_hostname }}.{{ .Values.DNS_ZONE }}$; | ||
|
||
# Assemble the two captured vars | ||
set $pr_number_service "${pr_number}-${service}"; | ||
|
||
access_log /dev/stdout; | ||
error_log /dev/stderr; | ||
|
||
# 'internal' directive designates this location is nginx-internal-only | ||
# cf. http://nginx.org/en/docs/http/ngx_http_core_module.html#internal | ||
location /oauth2/auth { | ||
internal; | ||
proxy_pass http://localhost_oauth2_proxy; | ||
} | ||
|
||
# initiate the oauth flow | ||
location /oauth2/start { | ||
auth_request off; | ||
proxy_pass http://localhost_oauth2_proxy; | ||
} | ||
|
||
# Presents the initial login page with "Sign in with a XYZ account" button. | ||
# Also logs the user out by clearing their _oauth_cookie. | ||
location /oauth2/sign_in { | ||
auth_request off; | ||
rewrite_log on; | ||
if ($arg_initial = "true") { | ||
proxy_pass http://localhost_oauth2_proxy/oauth2/sign_in?iap_redirect=${arg_iap_redirect}; | ||
break; | ||
# we continue processing this request | ||
# http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#break | ||
} | ||
|
||
# This is currently where the callback? oauth flow winds up after valid | ||
# authentiation with a valid _oauth_cookie. | ||
|
||
# TODO(tamsky): determine if we can move iap_redirect to a unique path | ||
# instead of piggybacking on the /oauth2/sign_in location | ||
if ($arg_iap_redirect) { | ||
# redirect to final desination, trailing-'?' tells nginx to drop current $query_string | ||
rewrite ^.*$ ${arg_iap_redirect}? redirect; | ||
} | ||
|
||
# This 'proxy_pass' URL is what generates the start-of-oauth-flow: | ||
proxy_pass http://localhost_oauth2_proxy/oauth2/sign_in?iap_redirect=${pr_number_service}.{{ .Values.iap_hostname }}.{{ .Values.DNS_ZONE }}${request_uri}; | ||
} | ||
|
||
location /oauth2/callback { | ||
auth_request off; | ||
proxy_pass http://localhost_oauth2_proxy; | ||
} | ||
|
||
location / { | ||
# All paths (not matched above) are protected by the 'auth_request' directive. | ||
auth_request /oauth2/auth; | ||
|
||
# Headers we include in the auth_request: | ||
auth_request_set $auth_user $upstream_http_x_authenticated_email; | ||
|
||
# TODO(tamsky): verify we need 'initial=true' pieces. | ||
error_page 401 =307 $scheme://{{.Values.iap_hostname}}.{{ .Values.DNS_ZONE }}/oauth2/sign_in?initial=true&iap_redirect=$scheme://${pr_number_service}.{{ .Values.iap_hostname }}.{{ .Values.DNS_ZONE }}$request_uri; | ||
|
||
# Headers that are set in the request sent to the oauth2_proxy: | ||
proxy_set_header x-forwarded-user $auth_user; | ||
proxy_set_header Upgrade $http_upgrade; | ||
proxy_set_header Connection $http_connection; | ||
|
||
# Lookup hostname using DNS and proxy the current request to service_ip_address:80 | ||
proxy_pass http://${service}.${pr_number}.svc.cluster.local.; | ||
# trailing dot is correct | ||
} | ||
|
||
# TODO(tamsky): add 'location /logout {}' | ||
|
||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
proxy_set_header X-Upstream-Response-Time $upstream_response_time; | ||
proxy_next_upstream error http_500; | ||
proxy_set_header Host $host; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update
description