Can k8s webhook self-sign pan-domain certificate - ssl

k8s webhook requires tls verification, the official document says that the server certificate requires <svc_name>.<svc_namespace>.svc.
But when I deploy with helm, I may not know which namespace will be deployed in. The svc_name generally does not change, so is there some way to match any namespace. such as <svc_name>.<any_namespace>.svc.
Is there a method implementation that works for arbitrary namespaces?
I really appreciate any help with this
k8s version is 1.18
Attach a sample of my self-signed certificate
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
CN = webhook.kube-system.svc
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectAltName = #alt_names
[alt_names]
DNS.1 = webhook.kube-system.svc

Posted community wiki answer for better visibility. Feel free to expand it.
EDIT:
The workaround presented by the original poster (#moluzhui):
At present, I provide ValidatingWebhookConfiguration in chart/template in advance and write it through .Files.Get
As stated in the official documentation:
Note: When using clientConfig.service, the server cert must be valid for <svc_name>.<svc_namespace>.svc.
The namespace name is required - this is how DNS in Kubernetes works - by using service and namespace name.
However, there is a good article which presents best practices of managing TLS certificates for Kubernetes Admission Webhooks - 5 Ways of Managing TLS Certificates for your Kubernetes Admission Webhooks. Maybe some of them will be useful to you and will be solution for your issue:
for helm - use Certificator project and Helm Hooks - it automatically patches caBundle field
setup init container to create a certificate and provide CA bundle to the API server
generate certificate with cert-manager CA Injector and inject them to WebhookConfiguration
You can also set up URL with a location of the webhook, where you don't have to use caBundle:
Expects the TLS certificate to be verified using system trust roots, so does not specify a caBundle.
Answering your comment:
Well, then I can only use multiple DNS(1,2,3...) to preset the name space that may be deployed. Does this affect efficiency?
Probably depends how many namespaces you want to deploy, but for sure it is not good practice.
Another solution from the comment (thanks to #JWhy user):
You may create another service at a predictable location (i.e. in a specific namespace) and link that to your actual service in the less predictable namespace. See stackoverflow.com/a/44329470/763875

Related

Allow kubernetes storageclass resturl HTTPS with self-signed certificate

I'm currently trying to setup GlusterFS integration for a Kubernetes cluster. Volume provisioning is done with Heketi.
GlusterFS-cluster has a pool of 3 VMs
1st node has Heketi server and client configured. Heketi API is secured with a self-signed certificate OpenSSL and can be accessed.
e.g. curl https://heketinodeip:8080/hello -k
returns the expected response.
StorageClass definition sets the "resturl" to Heketi API https://heketinodeip:8080
When storageclass was created successfully and I try to create a PVC, this fails:
"x509: certificate signed by unknown authority"
This is expected, as ususally one has to allow this insecure HTTPS-connection or explicitly import the issuer CA (e.g. a file simply containing the pem-String)
But: How is this done for Kubernetes? How do I allow this insecure connection to Heketi from Kubernetes, allowing insecure self-signed cert HTTPS or where/how do I import a CA?
It is not an DNS/IP problem, this was resolved with correct subjectAltName settings.
(seems that everybody is using Heketi, and it seems to be still a standard usecase for GlusterFS integration, but always without SSL, if connected to Kubernetes)
Thank you!
To skip verification of server cert, caller just need specify InsecureSkipVerify: true. Refer this github issue for more information (https://github.com/heketi/heketi/issues/1467)
In this page, they have specified a way to use self signed certificate. Not explained thoroughly but still can be useful (https://github.com/gluster/gluster-kubernetes/blob/master/docs/design/tls-security.md#self-signed-keys).

openSSL subjectAltNames unclear

I'm setting up a webserver is for development and testing purposes, strictly local, no access from the Internet, but needs to be conform the production environment as close as possible, including SSL.
So I have set up a local CA on the server, created a server request using SubjectAltNames for several nodes running on them, and signed it using the just created CA, and instructed apache to user this setup.
CN in both CA as server is tdc.nl - which is the 'domain' I'm using locally. It has sites manage.tdc.nl, www.tdc.nl, so in the server-request, I defined:
[ v3-req ]
...
subjectAltNames = #alt_names
...
[ alt_names ]
DNS.1 = tdc.nl
DNS.2 = manage.tdc.nl
DNS.3 = www.tdc.nl
DNS.4 = mail.tdc.nl
All names (except mail.tdc.nl) are registered in \Windows\System32\drivers\etc\hosts on the workstation that I use to access each of these servers, and in the server itself. I installed the CA certificate on my workstation as trusted base certificate as prompted in many descriptions.
Then I access https://manage.tdc.nl with different browsers.
Chrome signals NET::ERR_CERT_COMMON_NAME_INVALID, Edge signals DLG_FLAGS_SEC_CERT_CN_INVALID. Though both allow me to continue, I want to get on without error messages. However, it's weird that Firefox seems to be happy, even without installing the CA certificate, just accepts the link, and I can proceed without message.
I checked the server certificate and that notes the alternate names, but these are missing in the CA certificate. Should the subjectAlternateNames also be specified in the CA? The documentation I read doesn't show anything on that.
Doublechecked config for CA and docs I used: found I was missing
copy_extensions = copy
Redone signing, now subjectAltNames are in server certificate
After restarting Apache, it worked.

Self-signed certificate for device with local IP

Scenario:
We have a device similar to a WiFi router that has UI and API exposed
The device will run on any LAN out of our control, just like a WiFi router runs on any house.
The device doesn't belong to any domain and is accessed through its IP address (i.e. 192.168.1.100) with a browser.
The protocol shall be HTTPS
The software used is .net Core/Kestrel on Windows
Currently we have warnings in all browsers telling that the device has an invalid certificate.
Constraint: The device shall be accessible by any machine (desktop/tablet) and cannot install or configure anything in the client machines.
The question is:
What it the best way to remove the warning? We read that there cannot be regular certificates for private/local IPs.
Self-signed certificates seem to work for few days and then the error shows up again.
There is no way to issue SSL certificate for an IP address; you have to have an actual name which you create the certificate for. In order to get such a name, you need a DNS. Since you don’t have access to the internal DNS of that local network, you will have to use a public DNS server for this.
This assumes that devices within that network do actually have internet access. If they don’t, then you’re completely out of luck.
If there is internet access, then you can simply make a public (sub-)domain point to your local IP address. Basically, configure the DNS for a domain that you own so that there is an A entry on the domain or one of its subdomains, that points to your local IP address 192.168.1.100.
That way, you can communicate that public domain to others, and when they try to resolve the domain, they will hit the DNS which will give the local IP address. So devices within that network can then get to your device and access it. Since they are accessing it then through that domain, a certificate for that exact domain would be generally accepted.
In theory, this works pretty well. In practice this can be a bit complicated or expensive though. Server certificates expire, so you will have to include the certificate (securely!) inside your device and also provide some means to update it eventually when it would expire. Free certificates, like from letsencrypt, will expire within a few weeks, but money will be able to buy you certificates that expire less quickly.
But in the end, it will still be somewhat painful. But not because of the domain name, but rather because of the certificate – at least if you want a certificate that is automatically trusted. Otherwise, you would be back at the beginning.
So If I understand it corretly, without internet access and without
access to internal DNS, there is no way to allow clients (within local
network) to access a REST api listening on "some" device within the
local network over HTTPS. Right?
That is not correct. You can use a wildcard certificate, generated with e.g. openssl and communicate securely over TLS encryption. Just the signing is not trusted, so modern Browsers will show the big warning "Not secure". That is awfully wrong. It is way more secure compared to plain http, because it is not sure you're talking to the server you're expecting but you talk securely encrypted.
In plain http it will be enough to just listen the packets flying by. With https you need to pretend to be the server and issue a certificate and the right endpoints. So a much bigger effort and for most use cases in local networks a sufficient level of security.
Generate Certificate
#!/bin/bash
CONFIG="
HOME = /var/lib/cert
[ req ]
default_bits = 4096
default_md = sha256
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = v3_req
[ req_distinguished_name ]
countryName= YourCountryCode
stateOrProvinceName= YourState
localityName= YourTown
organizationName= YourCompany
organizationalUnitName= YourUnit
commonName= *
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = email:whatever#localhost
"
openssl genrsa -out /var/usr/cert/name.key 4096
openssl req -x509 -new -nodes -key /var/usr/cert/name.key \
-config <(echo "$CONFIG") -days 365 \
-out /var/usr/cert/name.crt
Apply it to your service.
For browsers it'll show this big ugly message
For apps connecting to services you'll often need to set a flag, disabling signing checks like:
curl -k or --insecure
influx -ssl -unsafeSsl
(google helps for your application)

Creating self signed certificate for domain and subdomains - NET::ERR_CERT_COMMON_NAME_INVALID

I followed this tutorial for creating Signed SSL certificates on Windows for development purposes, and it worked great for one of my domains(I'm using hosts file to simulate dns). Then I figured that I have a lot of subdomains, and that would be a pain in the ass to create a certificate for each of them. So I tried creating a certificate using wildcard in Common field as suggested in some of the answers at serverfault. Like this:
Common Name: *.myserver.net/CN=myserver.net
However, after importing this certificate into Trusted Root Certification Authority, I'm getting NET::ERR_CERT_COMMON_NAME_INVALID error in Chrome, for main domain and all of its subodmains, for example: https://sub1.myserver.net and https://myserver.net.
This server could not prove that it is myserver.net; its security certificate
is from *.myserver.net/CN=myserver.net.
This may be caused by a misconfiguration or an attacker intercepting your connection.
Is there something wrong in Common Name field that is causing this error?
Chrome 58 has dropped support for certificates without Subject Alternative Names.
Moving forward, this might be another reason for you encountering this error.
A workaround is to add the domain names you use as "subjectAltName" (X509v3 Subject Alternative Name). This can be done by changing your OpenSSL configuration (/etc/ssl/openssl.cnf on Linux) and modify the v3_req section to look like this:
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = #alt_names
[alt_names]
DNS.1 = myserver.net
DNS.2 = sub1.myserver.net
With this in place, not forget to use the -extensions v3_req switch when generating your new certificate. (see also How can I generate a self-signed certificate with SubjectAltName using OpenSSL?)
As Rahul stated, it is a common Chrome and an OSX bug. I was having similar issues in the past. In fact I finally got tired of making the 2 [yes I know it is not many] additional clicks when testing a local site for work.As for a possible workaround to this issue [using Windows], I would using one of the many self signing certificate utilities available.Recommended Steps:
Create a Self Signed Cert
Import Certificate into Windows Certificate Manager
Import Certificate in Chrome Certificate ManagerNOTE: Step 3 will resolve the issue experienced once Google addresses the bug...considering the time in has been stale there is no ETA in the foreseeable future.**As much as I prefer to use Chrome for development, I have found myself in Firefox Developer Edition lately. which does not have this issue.Hope this helps :)
Create openssl.conf file:
[req]
default_bits = 2048
default_keyfile = oats.key
encrypt_key = no
utf8 = yes
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = US
ST = Cary
L = Cary
O = BigCompany
CN = *.myserver.net
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = #alt_names
[alt_names]
DNS.1 = myserver.net
DNS.2 = *.myserver.net
Run this comand:
openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout app.key -out app.crt -config openssl.conf
Output files app.crt and app.key work for me.
Your wildcard *.example.com does not cover the root domain example.com but will cover any variant on a sub-domain such as www.example.com or test.example.com
The preferred method is to establish Subject Alternative Names like in Fabian's Answer but keep in mind that Chrome currently requires the Common Name to be listed additionally as one of the Subject Alternative Names (as it is correctly demonstrated in his answer). I recently discovered this problem because I had the Common Name example.com with SANs www.example.com and test.example.com, but got the NET::ERR_CERT_COMMON_NAME_INVALID warning from Chrome. I had to generate a new Certificate Signing Request with example.com as both the Common Name and one of the SANs. Then Chrome fully trusted the certificate. And don't forget to import the root certificate into Chrome as a trusted authority for identifying websites.
I think it may be a bug in chrome. There was a similar issue long back:
See this.
Try in a different browser. I think it should work fine.
If you're tired of this error. You can make Chrome not act out like this. I'm not saying it's the best way just saying it's a way.
As a workaround, a Windows registry key can be created to allow Google Chrome to use the commonName of a server certificate to match a hostname if the certificate is missing a subjectAlternativeName extension, as long as it successfully validates and chains to a locally-installed CA certificates.
Data type: Boolean [Windows:REG_DWORD]
Windows registry location: HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome
Windows/Mac/Linux/Android preference name: EnableCommonNameFallbackForLocalAnchors
Value: 0x00000001 (Windows), true(Linux), true (Android), (Mac)
To create a Windows registry key, simply follow these steps:
Open Notepad
Copy and paste the following content into notepad
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome]
"EnableCommonNameFallbackForLocalAnchors"=dword:00000001
Go to File > Save as
Filename: any_filename.reg
Save as type: All Files
Select a preferred location for the file
Click on Save
Double click on the saved file to run
Click on Yes on the Registry Editor warning
Found this information on Symantec support page:
https://support.symantec.com/en_US/article.TECH240507.html
For everyone who is encountering this and wants to accept the risk to test it, there is a solution: go to Incognito mode in Chrome and you'll be able to open "Advanced" and click "Proceed to some.url".
This can be helpful if you need to check some website which you are maintaining yourself and just testing as a developer (and when you don't yet have proper development certificate configured).
Of course this is NOT FOR PEOPLE using a website in production where this error indicates that there is a problem with website security.
The answers provided did not work for me (Chrome or Firefox) while creating PWA for local development and testing. DO NOT USE FOR PRODUCTION! I was able to use the following:
Online certificate tools site with the following options:
Common Names: Add both the "localhost" and IP of your system e.g. 192.168.1.12
Subject Alternative Names: Add "DNS" = "localhost" and "IP" = <your ip here, e.g. 192.168.1.12>
"CRS" drop down options set to "Self Sign"
all other options were defaults
Download all links
Import .p7b cert into Windows by double clicking and select "install"/ OSX?/Linux?
Added certs to node app... using Google's PWA example
add const https = require('https');
const fs = require('fs'); to the top of the server.js file
comment out return app.listen(PORT, () => { ... }); at the bottom of server.js file
add below https.createServer({
key: fs.readFileSync('./cert.key','utf8'),
cert: fs.readFileSync('./cert.crt','utf8'),
requestCert: false,
rejectUnauthorized: false
}, app).listen(PORT)
I have no more errors in Chrome or Firefox

Setting up httpS for multiple domain

I need to setup https for multiple domians xxxx.com xxxx.net (with single common certificate)
CA where we buying certificate ask to create Certificate Signing Request (CSR), but when I'm generating it with openssl - it asks only for one name
how to make one CSR for multiple domains ?
Avoid certificates with multiple CNs (as suggested in comments), that's not how the specifications (RFC 2818 and RFC 6125) say it should work and, although it may work in some clients applications, it will usually fail. From RFC 2818:
If a subjectAltName extension of type dNSName is present, that MUST
be used as the identity. Otherwise, the (most specific) Common Name
field in the Subject field of the certificate MUST be used. Although
the use of the Common Name is existing practice, it is deprecated and
Certification Authorities are encouraged to use the dNSName instead.
Instead, generate certificates (or CSR) with multiple Subject Alternative Names (SANs).
If you're using OpenSSL, edit your openssl.cnf (or edit a copy) and set these properties, in the relevant sections ([req] and [ v3_req ]):
[req]
req_extensions = v3_req
[v3_req]
subjectAltName=DNS:www.example1.com,DNS:www.example2.com,DNS:www.example3.com
There's also a nice trick to use an environment variable for this (rather in than fixing it in a configuration file) here: http://www.crsr.net/Notes/SSL.html
You may also want to have one of them (any) in the CN.
(You may also be interested in this answer.)