I am trying to make my ingress run over https but I'm getting HTTP ERROR 403, and I don't know what am I missing here.
I am trying to access them on my-local-domain.com and I added that entry on my etc/hosts file as
127.0.0.1 my-local-domain.com so I can access it that way.
Here's my Issuer
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: cert-issuer
namespace: my-namespace
spec:
selfSigned: {}
Here's my Certificate
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: self-signed-cert
namespace: my-namespace
spec:
secretName: my-secret-tls
dnsNames:
- my-local-domain.com
- www.my-local-domain.com
issuerRef:
name: cert-issuer
While here is my nginx ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-service
labels:
name: ingress-service
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
namespace: my-namespace
spec:
tls:
- hosts:
- my-local-domain.com
- www.my-local-domain.com
secretName: my-secret-tls
rules:
- host: my-local-domain.com
http:
paths:
- path: /api/(.*)
pathType: Prefix
backend:
service:
name: web-api
port:
number: 443
- path: /(.*)
pathType: Prefix
backend:
service:
name: web-client
port:
number: 80
nginx.conf for my web-client service
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
gzip on;
}
And when I try to access it with https://my-local-domain.com
Access to my-local-domain.com was denied
You don't have authorization to view this page.
HTTP ERROR 403
I also tried to run
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "//CN=my-local-domain.com\O=my-local-domain.com" -addext "subjectAltName = DNS:my-local-domain.com"
kubectl create secret tls tls-secret --key tls.key --cert tls.crt -n my-namespace
remove Certificate and CertificateIssuer and add tls-secret as secretName in ingress, as well as added those tls.key and tls.crt to my web-client nginx and updated it to:
server {
listen 443 ssl default_server;
ssl_protocols SSLv3 TLSv1;
server_name www.my-local-domain.com my-local-domain.com;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log info;
keepalive_timeout 75 75;
ssl_certificate /etc/ssl/certs/self-signed.crt;
ssl_certificate_key /etc/ssl/private/self-signed.key;
ssl_session_timeout 5m;
add_header Strict-Transport-Security "max-age=7200";
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
p.s. when doing this, i run everyrhing on port 443 instead of 80.
When I remove the tls part from my ingress, then it does work through HTTP. And I also tried to change my dns/host from my-local-domain.com to be only localhost but still the same. And even if I try to access https://localhost I get that HTTP ERROR 403.
I don't know if this will help, but here are some advices:
Determine the source of your error
You provide us a lot of code, but no details of the error. Is the 403 thrown by your webservice, your api or by your ingress-controller? You can check that in the error-page. Errors from ingress-controller usally contains somethink like "openresty" in footer. But it hardly depends on your ingress-controller which are you using in your k8s.
You can also check the logs of your containers (nginx write the logs to /var/log/nginx/error.log). Here you can find some more detailed informations why you're getting a 403.
Let the cluster handle SSL-termination
Don't put the ssl-certifications into the containers. It will increase hardly the complexity of your app(s).
It is a lot easier, when the cluster take care about that. So your app can be faster deployed on other clusters with others environments.
Avoid the cert-manager, when using self-signed certs
As you already tested, but I suggest to use the cert-manager only, when you need certificates from lets encrypt. Otherwise it will increase the complexity again.
Don't mix up HTTP and HTTPS
Your webapi using HTTPS for the internal communication (internal means: ingress-controller -> webapi-service, which is usually unencrypted) ... but not for your web-server.
Keep things simple - HTTPS for all or for nobody.
Try to avoid url-rewrite
Whenever when possible, try to avoid url-rewrite. I see very often problems with it, so I suggest to avoid it.
I know this is not always possible, but when all componets are developed by you ... why did you need it at all? Here is your ingress in "easy":
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-service
labels:
name: ingress-service
namespace: my-namespace
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
tls:
- hosts:
- my-local-domain.com
- www.my-local-domain.com
secretName: my-secret-tls
rules:
- host: my-local-domain.com
http:
paths:
- path: /api/
backend:
service:
name: web-api
port:
number: 80
- path: /
backend:
service:
name: web-client
port:
number: 80
Rootless is the best
Not very important for your problem, but instead of the standard nginx-image, use the unprivileged nginx-image. If your service (in this case nginx) got hacked, then the hacker has the same privileges like nginx. This means, he can easily install tools into the nginx-container and do very bad things.
If you're using the unprivileged image, than the hacker can ... almost nothing. He needs a second exploit to escalate his rights.
Good luck to find your error. We are happy, when you share your next steps with us.
Related
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.
I am setting a reverse proxy using kubernetes nginx-ingress, but I don't know how to add nginx parameters to the configuration, specifically: proxy_ssl_server_name. How do I set ingress parameters in yaml configurations?
I already tried using the server-snippet annotation, but it seems like it's not adding the parameter to the nginx.conf file in the cluster pods.
Here is the current code for the reverse proxy:
kind: Service
apiVersion: v1
metadata:
name: formstack
namespace: serves
spec:
type: ExternalName
externalName: fluidsignal.formstack.com
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: formstack
namespace: serves
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/upstream-vhost: "fluidsignal.formstack.com"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
tls:
- hosts:
- fluidattacks.com
secretName: fluidattacks-cert
rules:
- host: fluidattacks.com
http:
paths:
- backend:
serviceName: formstack
servicePort: 443
path: /forms(.*)
After setting up the proxy, I get a 502 Bad Gateway error from Nginx. After looking at the pods logs, I see I'm getting the following openssl error: SSL: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:SSL alert number 40, which is why I want to add the parameter I mentioned before.
I just figured out that I was indeed using the right annotation: nginx.ingress.kubernetes.io/server-snippet,
But I needed to add an extra parameter: proxy_ssl_name
Adding the following code fixed the problem:
nginx.ingress.kubernetes.io/server-snippet: |
proxy_ssl_name fluidsignal.formstack.com;
proxy_ssl_server_name on;
Everything seems to be working fine now :D
I'm trying to use the certificates obtained through digicert to enable https on my nginx-ingress. We've obtained a wildcard certificate and I have the following files.
domain_name_2019-2021.csr
domain_name_2019-2021.key
domain_name_2019-2021.pem
DigiCertCA2_2019-2021.pem
star_domain_name_2019_2021.pem
TrustedRoot.pem
I've created the tls secrets by running the following commands
kubectl create secret tls tls-secret --key ${KEY_FILE} --cert ${CERT_FILE}
And used these secrets in my ingress configuration like so
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-service
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
tls:
- hosts:
- {{ .Values.host }}
secretName: tls-secret
rules:
- host: {{ .Values.host }}
http:
paths:
- path: /
backend:
serviceName: service_name
servicePort: 443
However when browse to subdomain.domain_name.com I get an invalid certificate with an error of This certificate has not been verified by a third party. And the certificate its using says Kubernetes Ingress Controller Fake Certificate
you can follow this, to install Jetstack cert-manager, once you make this installed, please follow this stackoverflow post.
It will solve your query.
The current certificates created by you are not necessary for this, here the certificate will be automatically created by jetstack once it would be able to get the acme challenge verified, for that verification sake you need to map the DNS or hostname to the Load balancer IP of nginx.
This should solve your purpose to get http to https conversion
I have a K8s cluster (v1.12.8-gke.10) in GKE and have a nginx ingress with hosts rules. I am trying to enable TLS using cert-manager for ingress routes. I am using a selfsign cluster issuer. But, when I access the site over HTTPS, I am still getting the default K8s certificate. (The certificate is only valid for the following names: kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local)
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
namespace: test
name: test
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/ingress.allow-http: "false"
nginx.ingress.kubernetes.io/rewrite-target: /
certmanager.k8s.io/cluster-issuer: selfsign
spec:
tls:
- secretName: test
hosts:
- test.example.com
rules:
- host: test.example.com
http:
paths:
- path: /
backend:
serviceName: test
servicePort: 80
I have checked the following and is working fine:
A cluster issuer named "selfsign"
A valid self-signed certificate backed by a secret "test"
A healthy and running nginx ingress deployment
A healthy and running ingress service of type load-balancer
I think it's issue of clusterissuer
Just have a look at my cluster issuer and check
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: it-support#something.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: prod
# Enable the HTTP-01 challenge provider
http01: {}
Check for the right url to get production-grade certificates:
server: https://acme-v02.api.letsencrypt.org/directory
If your server url is something like this :
server: https://acme-staging-v02.api.letsencrypt.org/directory
which means you are applying for the staging certificate which may occur the error.
I've followed the tutorial from Digital Ocean and was able to enable TLS using cert-manager for ingress routes using Helm, Tiller, Letsencrypt and Nginx Ingress controller in GKE.
Instead of host test-example.com, I used my own domain name and spun up dummy backend services (echo1 and echo2) for testing purposes.
After followed the tutorial and to verify that HTTPS is working correctly, try to curl the host:
$ curl test.example.com
you should see a 308 http response (Permanent Redirect). This indicates that HTTP requests are being redirected to use HTTPS.
On the other hand, try running curl on:
$ curl https://test.example.com
Should show you the site response.
You can run the previous commands with the verbose -v flag to check into the certificate handshake and to verify the certificate information.
I want to secure my K8s application with TLS. I've generated 2 SSL certificates with Let's Encrypt: one for kamerbaas.nl and one for gateway.kamerbaas.nl. I created two secrets from the files tls.crt and tls.key for each domain.
The YAML file of my Ingress is as follows:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: gateway-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- gateway.kamerbaas.nl
secretName: gateway.kamerbaas.nl
- hosts:
- kamerbaas.nl
secretName: kamerbaas.nl
rules:
- host: gateway.kamerbaas.nl
http:
paths:
- path: /*
backend:
serviceName: kb-gateway
servicePort: 80
- host: kamerbaas.nl
http:
paths:
- path: /*
backend:
serviceName: kb-frontend
servicePort: 80
The catch: When I go to https://gateway.kamerbaas.nl, it works; it's showing a green lock. When I go to https://kamerbaas.nl however, it says it's not secure, since it's trying to use the certificate of gateway.kamerbaas.nl.
I've ruled out the possibility that it's a cache issue, and I've ensured that I didn't mix my certificate files up. I'm 100% sure the secrets are right.
Why is kamerbaas.nl trying to use the certificate of gateway.kamerbaas.nl?
Ps. gateway.kamerbaas.nl has a node-express server running with HTTPS. I've loaded my certificates there as well. kamerbaas.nl has a node server without https, could that be the problem? I'm guessing it doesn't matter, since my Ingress rules only points to port 80 of my services, which is the port for unsecured HTTP.