'Enable SSL termination for superset at ingress controller
We have deployed superset to an EKS cluster. We want TLS terminated at the Ingress controller.
This is how I set up the entire setup.
GSLB Vip → Nginx ingress controller → http → ingress → service → pod
When we enter the URL/login/ on the browser, it gets redirected to login again after we provide the credentials. On a new tab if I then open /superset/welcome it works just fine. We assume the problem is because Superset redirects initially to http from https, and the login in inaccessible, but I could be wrong
When we curl the WIP, this is the response
curl -ivk https://superset-aws-ssl.g.xx.com/login
* Trying 10.20.xx.yy...
* TCP_NODELAY set
* Connected to superset-aws-ssl.g.xx.com (10.20.xx.66) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / xxx-xxx-xxx-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=superset-aws-ssl.g.xx.com; OU=xx; O=YY Inc.; ST=CC; C=US
* start date: Oct 13 20:01:12 2021 GMT
* expire date: Nov 12 20:01:11 2023 GMT
* issuer: CN=xx CA 1; OU=Certification Authority; O=xx; C=US
* SSL certificate verify ok.
> GET / HTTP/1.1
> Host: superset-aws-ssl.g.xx.com
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 308 PERMANENT REDIRECT
HTTP/1.1 308 PERMANENT REDIRECT
< Server: nginx/1.17.8
Server: nginx/1.17.8
< Date: Fri, 15 Oct 2021 06:47:44 GMT
Date: Fri, 15 Oct 2021 06:47:44 GMT
< Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
< Content-Length: 331
Content-Length: 331
< Connection: keep-alive
Connection: keep-alive
< Location: http://superset-aws-ssl.g.xx.com/login/
Location: http://superset-aws-ssl.g.xx.com/login/
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
* Connection #0 to host superset-aws-ssl.g.xx.com left intact
<p>You should be redirected automatically to target URL: <a href="http://superset-aws-ssl.g.xx.com/login/">http://superset-aws-ssl.g.xx.com/login/</a>. If not click the link.* Closing connection 0
In the above curl, we see that the location is getting redirected to HTTP. Plus login redirects to login
This is the ingress controller yaml
apiVersion: v1
kind: Service
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Forwarded-Proto: $scheme";
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-2:vvvv:certificate/xx-x-x-x-xxx
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: ELBSecurityPolicy-TLS-1-2-Ext-2018-06
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-type: nlb
finalizers:
- service.kubernetes.io/load-balancer-cleanup
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
name: ingress-nginx
namespace: ingress-nginx
resourceVersion: "6835154"
selfLink: /api/v1/namespaces/ingress-nginx/services/ingress-nginx
uid: xx-xx-xx-xx-xxxxx
spec:
clusterIP: xx.xxx.xxx.xxx
externalTrafficPolicy: Local
healthCheckNodePort: 30599
ports:
- name: http
nodePort: 31840
port: 80
protocol: TCP
targetPort: http
- name: https
nodePort: 30330
port: 443
protocol: TCP
targetPort: http
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
sessionAffinity: None
type: LoadBalancer
This is the ingress on top of the superset service:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "X-Forwarded-Proto: https";
name: superset-ingress
namespace: superset-ssl-v2
spec:
rules:
- host: https://superset-aws-ssl.g.xx.com
http:
paths:
- path: /(.*)
pathType: Prefix
backend:
serviceName: superset
servicePort: 8080
When we port forward the service, it works just fine.
Here is the values.yaml
bootstrapScript: |
#!/bin/bash
if [ ! -f ~/bootstrap ]; then echo "Running Superset with uid {{ .Values.runAsUser }}" > ~/bootstrap; fi
security_manager: |
""
extraConfigs:
datasources-init.yaml: |
databases:
- database_name: {{ .Values.datasources.druid_db_name }}
sqlalchemy_uri: {{ .Values.datasources.druid_uri }}
datasources:
druid_uri: ""
druid_db_name: ""
configMountPath: "/app/pythonpath"
extraConfigMountPath: "/app/configs"
image:
repository: docker.xx.com/superset
tag: latest
pullPolicy: Always
imagePullSecrets: []
service:
type: LoadBalancer
port: 8080
ingress:
enabled: false
annotations:
kubernetes.io/ingress.class: "plb.v1"
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- superset
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources:
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
limits:
cpu: 2000m
memory: 512Mi
requests:
cpu: 2000m
memory: 512Mi
##
## Superset node configuration
supersetNode:
command:
- "/bin/sh"
- "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; /usr/bin/docker-entrypoint.sh"
connections:
db_host: ""
db_port: ""
db_user: ""
db_pass: ""
db_name: ""
forceReload: false # If true, forces deployment to reload on each upgrade
initContainers:
- name: wait-for-postgres
image: docker.xx.com/busybox:latest
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: '{{ tpl .Values.envFromSecret . }}'
command: [ "/bin/sh", "-c", "until nc -zv $DB_HOST $DB_PORT -w1; do echo $DB_HOST; echo $DB_PORT; echo $DB_PASS; echo 'waiting for db'; sleep 1; done" ]
## Annotations to be added to supersetNode deployment
deploymentAnnotations: {}
## Annotations to be added to supersetNode pods
podAnnotations: {}
##
## Superset beat configuration (to trigger scheduled jobs like reports)
supersetCeleryBeat:
# This is only required if you intend to use alerts and reports
enabled: false
command:
- "/bin/sh"
- "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; celery beat --app=superset.tasks.celery_app:app --pidfile /tmp/celerybeat.pid --schedule /tmp/celerybeat-schedule"
forceReload: false # If true, forces deployment to reload on each upgrade
initContainers:
- name: wait-for-postgres
image: docker.xx.com/busybox:latest
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: '{{ tpl .Values.envFromSecret . }}'
command: [ "/bin/sh", "-c", "until nc -zv $DB_HOST $DB_PORT -w1; do echo 'waiting for db'; sleep 1; done" ]
## Annotations to be added to supersetCeleryBeat deployment
deploymentAnnotations: {}
## Annotations to be added to supersetCeleryBeat pods
podAnnotations: {}
configOverrides:
superset_config.py: |
CACHE_CONFIG = {
'CACHE_TYPE': 'simple',
'CACHE_DEFAULT_TIMEOUT': 300,
'CACHE_KEY_PREFIX': 'superset_simple'
}
DATA_CACHE_CONFIG = {
'CACHE_TYPE': 'simple',
"CACHE_NO_NULL_WARNING": True,
'CACHE_DEFAULT_TIMEOUT': 86400,
'CACHE_THRESHOLD': 86400,
'CACHE_KEY_PREFIX': 'superset_simple'
}
if "SUPERSET_HOME" in os.environ:
DATA_DIR = os.environ["SUPERSET_HOME"]
else:
DATA_DIR = os.path.join(os.path.expanduser("~"), ".superset")
LOG_FORMAT = "%(asctime)s:%(levelname)s:%(pathname)s:%(lineno)d:%(funcName)s:%(name)s:%(message)s"
LOG_LEVEL = "DEBUG"
# ---------------------------------------------------
# Enable Time Rotate Log Handler
# ---------------------------------------------------
# LOG_LEVEL = DEBUG, INFO, WARNING, ERROR, CRITICAL
ENABLE_TIME_ROTATE = True
TIME_ROTATE_LOG_LEVEL = "DEBUG"
FILENAME = os.path.join(DATA_DIR, "superset.log")
ROLLOVER = "midnight"
INTERVAL = 1
BACKUP_COUNT = 30
ENABLE_PROXY_FIX = True
FEATURE_FLAGS = {
"ROW_LEVEL_SECURITY": True,
"DASHBOARD_RBAC": True,
"DASHBOARD_CACHE": True,
"CLIENT_CACHE": True,
"ENABLE_PROXY_FIX": True
}
# from security_manager import MySecurityManager
# CUSTOM_SECURITY_MANAGER = MySecurityManager
enableProxyFix: "ENABLE_PROXY_FIX = True"
enable_oauth: |
ENABLE_PROXY_FIX = True
## Init job configuration
init:
# Configure resources
# Warning: fab commant consumes a lot of ram and can
# cause the process to be killed due to OOM if it exceeds limit
resources:
# limits:
# cpu:
# memory:
# requests:
# cpu:
# memory:
command:
- "/bin/sh"
- "-c"
- ". {{ .Values.configMountPath }}/superset_bootstrap.sh; . {{ .Values.configMountPath }}/superset_init.sh"
enabled: true
loadExamples: false
adminUser:
username: admin
firstname: admin
lastname: admin
email: [email protected]
password: admin
initContainers:
- name: wait-for-postgres
image: docker.xx.com/busybox:latest
imagePullPolicy: IfNotPresent
envFrom:
- secretRef:
name: '{{ tpl .Values.envFromSecret . }}'
initscript: |-
#!/bin/sh
echo "Upgrading DB schema..."
superset db upgrade
echo "Initializing roles..."
superset init
echo "Creating admin user..."
superset fab create-admin \
--username {{ .Values.init.adminUser.username }} \
--firstname {{ .Values.init.adminUser.firstname }} \
--lastname {{ .Values.init.adminUser.lastname }} \
--email {{ .Values.init.adminUser.email }} \
--password {{ .Values.init.adminUser.password }} \
|| true
{{ if .Values.init.loadExamples }}
echo "Loading examples..."
superset load_examples
{{- end }}
if [ -f "{{ .Values.extraConfigMountPath }}/datasources-init.yaml" ]; then
echo "Importing database connections.... "
superset import_datasources -p {{ .Values.extraConfigMountPath }}/datasources-init.yaml
fi
redis:
enabled: false
postgresql:
enabled: false
cluster:
enabled: false
nodeSelector: {}
tolerations: []
affinity: {}
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 80
timeoutSeconds: 5
periodSeconds: 10
failureThreshold: 2
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 60
timeoutSeconds: 5
periodSeconds: 10
failureThreshold: 2
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
