oauth2_proxy not asking for authentication - ssl

I am trying to setup oauth2_proxy on kubernetes to secure one of my single page application and I am using github as the authentication provider. I found this link useful and I followed this for doing my setup.
[https://alikhil.github.io/2018/05/oauth2-proxy-for-kubernetes-services/]
I have created an application on github and used my DNS Name in place of the HomePageURL and CallBackURL (https://auth.example.com replaced with https://example.com) because I do not have TLS secrets generated for auth.example.com. Rather I have TLS certificates generated for example.com because this domain belongs to me. I was getting error in nginx-controller that the certificate belongs to example.com and not to auth.example.com as these URLs have been used in defining the example Ingress and oauth proxy ingress and this was the basis for me to do the before mentioned chang.
My Ingresses looks like this
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: oauth2-proxy
annotations:
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: oauth2-proxy
servicePort: 4180
path: /oauth2
tls:
- hosts:
- example.com
secretName: oauth-proxy-tls
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: oauth-main-ingress
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
ingress.kubernetes.io/auth-url: https://example.com/oauth2/auth
ingress.kubernetes.io/auth-signin: https://example/oauth2/start?rd=https://$host$request_uri$is_args$args
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: example-service
servicePort: 80
path: /
tls:
- hosts:
- example.com
secretName: tls-secret
I want that whenever I click example.com it should display page for github authentication but in my case its directly giving the response which a service should give after successful authentication. I am not being asked to provide credentials. Also, I am getting error in my ingress controller logs as 7 controller.go:753] Error obtaining Endpoints for Service "default/oauth2-proxy": no object matching key "default/oauth2-proxy" in local store
Also, I tried replacing using nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy.oauth-proxy.svc.cluster.local:4180/oauth2/auth as mentioned in the link but it did not work for me. Can some one explain why is oauth2_proxy not asking for authentication and ingress is serving the requests directly without asking for authentication?

The annotation declared in the oauth-main-ingress yaml is incorrect.
As per the kubernetes/nginx-ingress documentation the annotation for external auth-url should be
nginx.ingress.kubernetes.io/auth-url: http://<oauth-service-url>
instead of
ingress.kubernetes.io/auth-url: http://<oauth-service-url>

Related

How to use wildcard certificates in Kubernetes with nginx ingress and cert-manager?

I am trying to deploy a React website together with an Express API on GKE. There should be multiple subdomains for both the website and the API, i.e.
domain.com, a.domain.com, b.domain.com, ... -> React app
api.domain.com, a.api.domain.com, b.api.domain.com -> Express API
The reasoning behind this is that the application is using cookie-based authentication, so the API and app need to be on the same subdomain (e.g. a.domain.com and api.a.domain.com).
Cert-manager and nginx ingress were deployed in the Kubernetes cluster with commands:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.2/cert-manager.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.5.1/deploy/static/provider/cloud/deploy.yaml
Everything works fine when I explicitly put all subdomains in the ingress and give each a separate TLS entry in the ingress. The certificates are successfully issued. But when using wildcards the certificates never get ready and when I try to open api.domain.com or domain.com it returns a "page not found" error.
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
cert-manager.io/issuer: letsencrypt-production
spec:
rules:
- host: "*.domain.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: react
port:
number: 80
- host: wordpress.domain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: wordpress
port:
number: 80
- host: "*.api.domain.com"
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api
port:
number: 9000
tls:
- hosts:
- "*.domain.com"
- domain.com
secretName: certificate-wildcard-domain
- hosts:
- "wordpress.domain.com"
secretName: certificate-wordpress-domain
- hosts:
- "*.api.domain.com"
- api.domain.com
secretName: certificate-api-domain
This is what is showing in the logs of the cert-manager pod:
cert-manager/orders "msg"="Failed to determine the list of Challenge resources needed for the Order" "error"="no configured challenge solvers can be used for this challenge" "resource_kind"="Order" "resource_name"="certificate-api-domain-9wvd9-2527200272" "resource_namespace"="default" "resource_version"="v1"
I do not understand the problem, why certificates are not issued correctly for wildcard entries and the website is not reachable, while e.g. for wordpress.domain.com the certificates are issued successfully and the website can be reached.
Issuer/ClusterIssuer solvers(Try Upgrade from v0.10 to v0.11)
Update the apiVersion on all your backed up resources from certmanager.k8s.io/v1alpha1 to cert-manager.io/v1alpha2
Support for the deprecated spec.http01 or spec.dns01 fields in Issuer and ClusterIssuer have been removed. Any Issuer or ClusterIssuer objects must be converted to use the equivalent spec.solvers[].http01 or spec.solvers[].dns01 syntax. You can read more about the Issuer resource in the configuration documentation.
Any issuers that haven't been converted will result in the cert-manager pod being unable to find any solvers at the expected location. This will result in errors like the following: no configured challenge solvers can be used for this challenge.
Let’s Encrypt issues wildcard certificates via ACMEv2 using the DNS-01 challenge. See ACME v2 Production Environment & Wildcard certificates for more technical information. Cert-manager.io: Docs: Configuration: ACME: DNS-01 contains details on the different options available on the Issuer resource's DNS01 challenge solver configuration.
Refer to No configured Challenge Solvers for ACME Prod only #2494 for more information, which may help to resolve your issue.

Kubernetes Ingress can't find SSL secret created by CertManager

I have been trying to genereate an SSL certificate from Let's Encrypt to my domain but cert-manager creates the secret and adds a random suffix, causing the NGINX ingress controller to not be able to find it:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/issuer: scaleway
kubernetes.io/tls-acme: "true"
spec:
rules:
- host: <DOMAIN>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-svc
port:
number: 80
tls:
- hosts:
- <DOMAIN>
secretName: tls-cert
Here is the error in the NGINX logs :
Error obtaining X.509 certificate: no object matching key "default/tls-cert" in local store
Error getting SSL certificate "default/storek8s.igesa.it": local SSL certificate default/storek8s.igesa.it was not found. Using default certificate
The secret is always created like this :
NAME TYPE DATA AGE
...
tls-secret-fjrm5 Opaque 1 60m
How do I disable adding the random suffix for the secret generated by Ingress ? Is there any workaround to solve this ?
At the moment I have too little information to give an exact answer. Are you for example using this Helm chart, what values does your values.yaml contain, and how did you setup your issuer?
Also, I know that tls secrets created by cert-manager should be of type kubernetes.io/tls and not Opaque as is the case in your situation. So there is definitly something going wrong there.

Adding SSL certificate to ingress controller vs adding it to ingress resource

Ingress controller deployment.yml
spec:
containers:
- args:
- /nginx-ingress-controller
- --default-backend-service=stratus/nginx-ingress-default-backend
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=ingress-controller-leader-nginx
- --enable-ssl-passthrough
Ingress resource.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: 'REPOSITORY_NAME'
namespace: service
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-passthrough: "false"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
tls:
- hosts:
- "xyz-development.com"
- secretName: ingress-secret-tls
rules:
- host: "xyz-development.com"
http:
paths:
- path: /service/
backend:
serviceName: 'REPOSITORY_NAME'
servicePort: 8080
the secret consists of a signed certificate with the CN as xyz-development.com
endpoint : xyz-development.com/service/swagger-ui.html
If I try to access the endpoint with the above config, I end up with "Your connection is not private" error.
But if I modify the ingress controller deployment.yml to
spec:
containers:
- args:
- /nginx-ingress-controller
- --default-backend-service=stratus/nginx-ingress-default-backend
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=stratus/ingress-controller-leader-nginx
- --enable-ssl-passthrough
- --default-ssl-certificate=service/ingress-secret-tls
Then the site is secure with my valid certificate.
Is this expected behaviour?
Even if the default ssl certificate flag is removed in the controller, shouldn't the secret mentioned in the ingress resource.yml be used?
Any other pointers or better practice would be appreciated
There's a minor typo in your manifest that's causing the first option to fail; it should not be a new element in the array of .spec.tls entries:
- secretName: ingress-secret-tls # wrong
secretName: ingress-secret-tls # correct
When you getting connection is not private, are you hitting the URL https://xyz-development.com/ or using an IP address instead? If you are using an IP address, NGINX will not load that TLS certificate, it might load other default certificate (kubernetes fake certificate if you are running on k8s)
And when you add that configuration into ingress controller directly, that will become your default TLS certificate, so whatever domain name that you are using, it will give you that certificate.

How can I make one route public in kubernetes ingress with auth-url set?

I am playing a little bit with path-based routing via Kubernetes ingresses (we use Nginx ingress). We have one service up and running behind authentication via external service like the one in the first snippet. This service is already used by other services in our ecosystem, however, as the development progresses, the service now has management API and we need to turn off the authentication for specific paths. According to this answer, this is not possible for basic auth and, according to what I have tried (second snippet), it is not possible for authentication via external service either. Is there any other way to allow specific paths without authentication without completely rearchitecting ingresses and domains/paths?
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: path-based-routing-1
annotations:
kubernetes.io/tls-acme: "true"
kubernetes.io/ingress.class: nginx-external
nginx.ingress.kubernetes.io/auth-url: http://authorizer.dev.svc.cluster.local
spec:
tls:
- hosts:
- 'routing.example.com'
secretName: routing.example.com
rules:
- host: 'routing.example.com'
http:
paths:
- path: /
backend:
serviceName: path-based-routing-1
servicePort: 80
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: path-based-routing-2
annotations:
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/auth-type: ""
kubernetes.io/ingress.class: nginx-external
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- 'routing.example.com'
secretName: routing.example.com
rules:
- host: 'routing.example.com'
http:
paths:
- path: /management-api
backend:
serviceName: path-based-routing-2
servicePort: 80

keycloak stops working when enabling tls behind nginx ingress controller

I need advice on how to configure nginx ingress controller and keycloak on eks kubernetes with TLS.
My first attempt was to get keycloak working without TLS. This works fine. But when I add TLS to the ingress definition, keycloak gives a Invalid parameter: redirect_uri error.
This is the working sample:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: keycloak-tls-test
namespace: keycloak-tls-test
spec:
rules:
- host: keycloak.test.myhops.com
http:
paths:
- backend:
serviceName: keycloak
servicePort: 80
When I add the tls part, I get the aforementioned error. See yaml file below.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: keycloak-tls-test
namespace: keycloak-tls-test
spec:
tls:
- hosts:
- keycloak.test.myhops.com
secretName: test-myhops-tls
rules:
- host: keycloak.test.myhops.com
http:
paths:
- backend:
serviceName: keycloak
servicePort: 80
Any suggestions on how to solve this? One online suggestion was to add https://keycloak.test.myhops.com/* to the Valid Redirect URL for the security-admin-console client in the master realm. This solved the invalid redirect_uri error, but then I only got blank pages. I could not find hints in the keycloak logging.
I figured out what caused the problem. It seems that when keycloak is used behind a reverse proxy that terminates the TLS, then keycloak needs proxy-address-forwarding to be set. For the docker container this means that the env var PROXY_ADDRESS_FORWARDING=true does the trick. So Ingress was correct and the keycloak deployment needed an extra environment variable.
Please not that ingress-nginx already set the correct headers for this to work:
X-Forwarded-For
X-Forwarded-Proto
Docker documentation
[keycloak documentation2