kubectl exec fails "cannot validate certificate because it doesn't contain any IP SANs" - ssl

I'm trying to use kubectl exec to enter one of my containers, but I'm getting stuck on this error.
$ kubectl exec -it ubuntu -- bash
error: Unable to upgrade connection: {
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "x509: cannot validate certificate for <worker_node_ip> because it doesn't contain any IP SANs",
"code": 500
}
I have configured kubectl with my CA certificate and admin keys, etc according to this guide https://coreos.com/kubernetes/docs/1.0.6/configure-kubectl.html
Update
I also found the same error in the API server's logs
E1125 17:33:16.308389 1 errors.go:62] apiserver received an error that is not an unversioned.Status: x509: cannot validate certificate for <worker_node_ip> because it doesn't contain any IP SANs
Does this mean I have configured the certs incorrectly on my worker/master nodes or on kubectl on my local machine?

If you used this command to create your certificate:
openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem
Then your issue can be resolved by doing the following as the 'client' cert uses an -extfile extfile.cnf:
echo subjectAltName = IP:worker_node_ip > extfile.cnf
openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial \
-out server-cert.pem -extfile extfile.cnf
You can specify any number of IP addresses, such as IP:127.0.0.1,IP:127.0.1.1 (non localhost as well).

If you're using Kubernetes with a Google Container Cluster, this may fix the issue as it did for me:
gcloud container clusters get-credentials <cluster-name> \
--project <project-name> --zone <zone>

That message is coming from the master trying to connect to the node (the flow of traffic is kubectl -> master API -> kubelet -> container). When starting the master, are you setting --kubelet_certificate_authority? If so, the master expects to be able to validate the kubelet's serving cert, which means it needs to be valid for the hostnames/IP addresses the master uses to connect to it.

Related

Page is working but showing "Not Secure" sign on browser (configured with Traefik v2 using self-signed cert)

I apologize if this is a silly rookie question, I'm not really experience in dealing with SSL / https so please help me out.
I have docker swarm setup and using Traefik to handle all the HTTPS services. when I first load the page (take grafana page for example), there is a warning page and I click "Advanced" and "Proceed (accept risk)", then the page display and working just fine, the only problem is the "Not Secure" sign showing on browser.
A few things could be contributing to this:
Self-created CA and self-signed cert: I'm at development stage so I created my own CA and signed the cert using openssl, and use this cert in Traefik dynamic configuration.
Command to generate CA:
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem
Command to generate self-signed cert:
openssl req -newkey rsa:2048 -days 365 -nodes -keyout key.pem -out req.pem
openssl x509 -req -in req.pem -days 365 -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out cert.pem
See attached screenshot for the errors of the certs: "Subject Alternative Name missing" & "This site is missing a valid, trusted certificate (net::ERR_CERT_AUTHORITY_INVALID)."
Chrome Dev Tool Certificate Error
Traefik configuration: Not using Let's Encrypt since I don't have an account, so using my own self-signed cert. I don't think this is the issue because I can see the page is using the cert I provided. But if anyone has similar experience with Traefik v2 maybe can give me some pointer if there is anything I set wrong?
Dynamic configuration file that declares the certs:
tls:
stores:
default:
defaultCertificate:
certFile: configuration/cert.pem
keyFile: configuration/key.pem
Question:
Is missing SAN a really important factor that will causes my page to be not secure? If yes, how can I add SAN while creating cert with openssl?
I understand that 2nd error "ERR_CERT_AUTHORITY_INVALID" means browser doesn't recognize the cert's validity. Does that mean I have to install my CA? Where and how to install it? Is it on docker swarm's manager node (this is where Traefik service and the certs at), or is it on any client's machine that trying to access the page?

CA Cert are only added at ca-bundle-trust.crt

Env:
Red Hat Enterprise Linux Server release 7.7 (Maipo)
# openssl version
OpenSSL 1.0.2g 1 Mar 2016
so a self-sign cert is generated using OpenSSL and the cacert.pem is put under /etc/pki/ca-trust/source/anchors/.
Now according to the man from update-ca-trust, the cmd should be run to add the cert into the trust store and the cert are to be added under /etc/pki/ca-trust/extracted/.
After running the said cmd, I see that the cert is added only to /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt. But most of the application like curl refer the OS ca trust at /etc/pki/ca-trust/extracted/openssl/ca-bundle.crt which is link to /etc/pki/tls/certs/ca-bundle.crt.
curl -v https://172.21.19.92/api
* About to connect() to 172.21.19.92 port 443 (#0)
* Trying 172.21.19.92...
* Connected to 172.21.19.92 (172.21.19.92) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
I understand that passing --cacert option would be a way to overcome it but I want to know why update-ca-trust only update ca-bundle-trust.crt and not ca-bundle.crt or the java Keystore extracted one as well /etc/pki/ca-trust/extracted/java/cacerts
The actual command that import certificates to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem is:
/usr/bin/p11-kit extract --format=pem-bundle --filter=ca-anchors --overwrite --comment --purpose server-auth $DEST/pem/tls-ca-bundle.pem
So the filters here are --filter=ca-anchors + --purpose server-auth. When you generate cert you have to add the purpose extendedKeyUsage=serverAuth explicitly:
openssl x509 -req -in $SRV_NAME.csr -CA $CA_NAME.crt -CAkey $CA_NAME.key -passin pass:"$PASS" -out $SRV_NAME.crt \
-days 3650 -CAcreateserial \
-extensions v3_ca \
-extfile <(echo "[v3_ca]"; echo "extendedKeyUsage=serverAuth"; echo "subjectAltName=$SRV_DNS_NAMES_TEXT,email:$SRV_EMAIL")

Mosquitto SSL certificate verify failed

I'm using Mosquitto version 1.4.8 on my test PC and the server. The server is accessible via ha.euroicc.com.
I've generated certificates and keys using the following script:
#! /usr/bin/env bash
# Create the CA Key and Certificate for signing Client Certs
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt
# Create the Server Key, CSR, and Certificate
openssl genrsa -out server.key 1024
openssl req -new -key server.key -out server.csr
# We're self signing our own server cert here. This is a no-no in production.
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
# Create the Client Key and CSR
openssl genrsa -out client.key 1024
openssl req -new -key client.key -out client.csr
# Sign the client certificate with our CA cert. Unlike signing our own server cert, this is what we want to do.
# Serial should be different from the server one, otherwise curl will return NSS error -8054
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt
# Verify Server Certificate
openssl verify -purpose sslserver -CAfile ca.crt server.crt
# Verify Client Certificate
openssl verify -purpose sslclient -CAfile ca.crt client.crt
I've put 'd', 'dd' and 'dddd' everywhere except for common name.
The common name for ca is 'd' and for server/client is 'ha.euroicc.com'.
CN for server/client needs to be this value, or it doesn't work at all!
My current mosquitto config file:
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
persistence_file mosquitto.db
log_dest syslog
log_dest stdout
log_dest topic
log_type error
log_type warning
log_type notice
log_type information
connection_messages true
log_timestamp true
password_file /etc/mosquitto/passwd
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
allow_anonymous false
port 8883
cafile /etc/mosquitto/certs/ca.crt
keyfile /etc/mosquitto/certs/server.key
certfile /etc/mosquitto/certs/server.crt
require_certificate true
I use this command to subscribe from test PC:
mosquitto_sub -h ha.euroicc.com -t "topic/test" -u "damjan" -P "damjan" -p 8883 --cafile ca.crt --key client.key --cert client.crt
And get these errors:
On test PC:
Error: A TLS error occurred.
On server:
1532564086: OpenSSL Error: error:14089086:SSL
routines:ssl3_get_client_certificate:certificate verify failed
1532564086: Socket error on client <unknown>, disconnecting.
I've tried without require_certificate set on the server side, and not using client key/cert on the client side and subscription works in this case. This means that username/password parameters are fine.
That means that I either generated certificates and keys with a problem, my mosquitto.conf is bad or I'm using mosquitto_sub with a problem. Maybe something else?
I'm really at loss here and can't figure out what to try next...
Every bit of information helps.
Had a similar issue while upgrading to 2.0 because of the updated TLS/SSL bindings several know weak algorithms are not supported anymore.
In my case the signature of the certificate was sha1WithRSAEncryption where sha1 is the weak part. The same would be for e.g. MD5.
Check your certificate with openssl x509 -text -noout -in your.crt
Resigning the certificate with sha256WithRSAEncryption fixed it for me.
There is no need to create a new key.
You can either create a new CSR from your existing key and information from your certificate:
openssl x509 -x509toreq -in sha1.crt -signkey sha1.key -out sha256-new.csr -sha256
or overwrite the algorithm while signing the existing CSR again:
openssl x509 -req -days 360 -in sha1.csr -CA DummyCA-DonotTrust.pem -CAkey DummyCA-DonotTrust.pem -CAcreateserial -out sha256.crt -sha256
Recent openssl version should use sha256 as default.
Debian has changed the default setting with openssl-1.1.1 see https://wiki.debian.org/ContinuousIntegration/TriagingTips/openssl-1.1.1 and set CipherString = DEFAULT#SECLEVEL=2.
To get a list of supported algorithms run: openssl ciphers -s -v 'ALL:#SECLEVEL=2'
Ok, so the problem was that I was generating all of the files on my test PC, and then sending it to the server.
I've tried generating everything on the server, and then copying appropriate files to my test PC, and everything works fine.
I've followed http://rockingdlabs.dunmire.org/exercises-experiments/ssl-client-certs-to-secure-mqtt . With lesser changes like hostname etc.
I had the same issue.
To fix it, while generating server.crt, answer to question 'Common Name' with IP address of the machine where Mqtt broker is going to be run.

x509 error when trying to login to a trusted (?) docker registry

I have set up a docker registry using harbor.
I have copied the appropriate certificates in /usr/share/local/ca-certificates and run sudo update-ca-certificates with success. (indicated the number of newly certs added).
When trying to login to the specific registry:
ubuntu#master1:/home/vagrant$ docker login my.registry.url
Username: pkaramol
Password:
Error response from daemon: Get https://my.registry.url/v2/: x509: certificate signed by unknown authority
However the following test succeeds:
openssl s_client -connect my.registry.url:443 -CApath /etc/ssl/certs/
...coming back with a lot of verbose output, the certificate itself and ending in :
Verify return code: 0 (ok)
curl also succeeds to the above https link (it fails when the site is not trusted).
Any suggestions?
If you read the documentation
Use self-signed certificates
Warning: Using this along with basic authentication requires to also trust the certificate into the OS cert store for some versions of docker (see below)
This is more secure than the insecure registry solution.
Generate your own certificate:
$ mkdir -p certs
$ openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt
Be sure to use the name myregistrydomain.com as a CN.
Use the result to start your registry with TLS enabled.
Instruct every Docker daemon to trust that certificate. The way to do this depends on your OS.
Linux: Copy the domain.crt file to /etc/docker/certs.d/myregistrydomain.com:5000/ca.crt on every Docker host. You do not need to restart Docker.
See below link for more details
https://docs.docker.com/registry/insecure/#use-self-signed-certificates

Trouble getting a self-signed cert working in Postman

I'm finally getting into using SSL on my personal sites, so I started by trying to make a multi-domain self signed cert for my local development (to handle api.mydomain.local, www.mydomain.local, and mydomain.local). I don't know if this was my first mistake, but...
As I couldn't find a single encompassing guide, I started by using two tutorials (from EasyEngine and DeveloperSide) to create my cert and install it on my host (Win10). I then used a DigitalOcean guide to figure out how to setup my Apache on my dev server (a Ubuntu VM); up to there, no big trouble, other than some minor issues caused by working from multiple guides at the same time.
I go ahead and try to hit my api in Chrome, it gives me an untrusted certificate value as expected, I pass and it works. As far as I know, this means the cert worked? However, when I try to hit my api in Postman, I get an error that indicates it can't accept an untrusted cert, which is fine, as it has a tutorial on how to fix that. However, it still doesn't work. I can't figure out what else to do to fix this, am I on the right track? Is my cert completely borked? Did I make a core mistake in trying to do a multi-domain cert?
One thing I did notice is that in the Dev Tools security tab, it says
Subject Alternative Name missing
So I'm not sure if that means my alt names aren't working, but if they weren't, it wouldn't try to load the certificate when I hit it in Chrome, right?
I had a similar issue while writing an article for my website on SSL certificates. So i wrote shell script for the same
#!/bin/bash
CERT_COMPANY_NAME=${CERT_COMPANY_NAME:=Tarun Lalwani}
CERT_COUNTRY=${CERT_COUNTRY:=IN}
CERT_STATE=${CERT_STATE:=DELHI}
CERT_CITY=${CERT_CITY:=DELHI}
CERT_DIR=${CERT_DIR:=certs}
ROOT_CERT=${ROOT_CERT:=rootCA.pem}
ROOT_CERT_KEY=${ROOT_CERT_KEY:=rootCA.key.pem}
# make directories to work from
mkdir -p $CERT_DIR
create_root_cert(){
# Create your very own Root Certificate Authority
openssl genrsa \
-out $CERT_DIR/$ROOT_CERT_KEY \
2048
# Self-sign your Root Certificate Authority
# Since this is private, the details can be as bogus as you like
openssl req \
-x509 \
-new \
-nodes \
-key ${CERT_DIR}/$ROOT_CERT_KEY \
-days 1024 \
-out ${CERT_DIR}/$ROOT_CERT \
-subj "/C=$CERT_COUNTRY/ST=$CERT_STATE/L=$CERT_CITY/O=$CERT_COMPANY_NAME Signing Authority/CN=$CERT_COMPANY_NAME Signing Authority"
}
create_domain_cert()
{
local FQDN=$1
local FILENAME=${FQDN/\*/wild}
# Create a Device Certificate for each domain,
# such as example.com, *.example.com, awesome.example.com
# NOTE: You MUST match CN to the domain name or ip address you want to use
openssl genrsa \
-out $CERT_DIR/${FILENAME}.key \
2048
# Create a request from your Device, which your Root CA will sign
if [[ ! -z "${SAN}" ]]; then
openssl req -new \
-key ${CERT_DIR}/${FILENAME}.key \
-out ${CERT_DIR}/${FILENAME}.csr \
-subj "/C=${CERT_COUNTRY}/ST=${CERT_STATE}/L=${CERT_CITY}/O=$CERT_COMPANY_NAME/CN=${FQDN}" \
-reqexts san_env -config <(cat /etc/ssl/openssl.cnf <(cat ./openssl-san.cnf))
else
openssl req -new \
-key ${CERT_DIR}/${FILENAME}.key \
-out ${CERT_DIR}/${FILENAME}.csr \
-subj "/C=${CERT_COUNTRY}/ST=${CERT_STATE}/L=${CERT_CITY}/O=$CERT_COMPANY_NAME/CN=${FQDN}"
fi
# Sign the request from Device with your Root CA
if [[ ! -z "${SAN}" ]]; then
openssl x509 \
-sha256 \
-req -in $CERT_DIR/${FILENAME}.csr \
-CA $CERT_DIR/$ROOT_CERT \
-CAkey $CERT_DIR/$ROOT_CERT_KEY \
-CAcreateserial \
-out $CERT_DIR/${FILENAME}.crt \
-days 500 \
-extensions san_env \
-extfile openssl-san.cnf
else
openssl x509 \
-sha256 \
-req -in $CERT_DIR/${FILENAME}.csr \
-CA $CERT_DIR/$ROOT_CERT \
-CAkey $CERT_DIR/$ROOT_CERT_KEY \
-CAcreateserial \
-out $CERT_DIR/${FILENAME}.crt \
-days 500
fi
}
METHOD=$1
ARGS=${*:2}
echo "Called with $METHOD and $ARGS"
if [ -z "${METHOD}" ]; then
echo "Usage ./sslcerts.sh [create_root_cert|create_domain_cert] <args>"
echo "Below are the environment variabls you can use:"
echo "CERT_COMPANY_NAME=Company Name"
echo "CERT_COUNTRY=Country"
echo "CERT_STATE=State"
echo "CERT_CITY=City"
echo "CERT_DIR=Directory where certificate needs to be genereated"
echo "ROOT_CERT=Name of the root cert"
echo "ROOT_CERT_KEY=Name of root certificate key"
else
${METHOD} ${ARGS}
fi
You can change the environment variables on the TOP and generate a self-signed certificate using below
$ SAN=DNS.1:*.tarunlalwani.com,DNS.2:tarunlalwani.com ./sslcerts.sh create_domain_cert '*.tarunlalwani.com'
Edit 1
Earlier browsers use to rely on FQDN, but now some of them have started using SAN which is "Subject Alternative Name". Generally openssl doesn't come up v3 extensions configured. SAN is a part of the v3 extensions. So when you generated a self signed certificated it has the correct FQDN (Full qualified domain name) but not SAN. Chrome will show error for these certificates but you will see firefox working fine.
PS: Taken from article http://tarunlalwani.com/post/self-signed-certificates-trusting-them/