This project is in MAINTENANCE mode
This is a webhook solver for NS1, for use with cert-manager, to solve ACME DNS01 challenges.
Tested with kubernetes v1.15.7, v1.16.2, and v1.17.0
helm, for installing charts.
Tested with helm v2.16.1 and v3.0.3
certmanager, the underlying framework this project plugs into.
Tested with cert-manager v0.13.0 and v1.0.3
We have a helm repo set up, so you can use that, or you can install directly from source:
$ helm install --namespace cert-manager cert-manager-webhook-ns1 ./deploy/cert-manager-webhook-ns1
$ kubectl --namespace cert-manager create secret generic ns1-credentials --from-literal=apiKey='Your NS1 API Key'
$ kubectl --namespace cert-manager apply -f secret_reader.yaml
Note that it may make more sense in your setup to use a ClusterRole
and
ClusterRoleBinding
here.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cert-manager-webhook-ns1:secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["ns1-credentials"]
verbs: ["get", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cert-manager-webhook-ns1:secret-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cert-manager-webhook-ns1:secret-reader
subjects:
- apiGroup: ""
kind: ServiceAccount
name: cert-manager-webhook-ns1
You'll need to edit and apply some resources, with something like:
$ kubectl --namespace cert-manager apply -f my_resource.yaml
Note that we use the cert-manager
namespace, but it may make more sense in
your setup to hame more nuanced namespace management.
letsencrypt
for example. We'll use
ClusterIssuer
here, which will be available accross namespaces. You may
prefer to use Issuer
. This is where NS1
API options are set (endpoint
,
ignoreSSL
).Staging issuer (optional):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com # REPLACE THIS WITH YOUR EMAIL!!!
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- dns01:
webhook:
groupName: acme.nsone.net
solverName: ns1
config:
apiKeySecretRef:
key: apiKey
name: ns1-credentials
# Replace this with your NS1 API endpoint if not using "managed"
endpoint: "https://api.nsone.net/v1/"
ignoreSSL: false
Production issuer:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com # REPLACE THIS WITH YOUR EMAIL!!!
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- dns01:
webhook:
groupName: acme.nsone.net
solverName: ns1
config:
apiKeySecretRef:
key: apiKey
name: ns1-credentials
# Replace this with your NS1 API endpoint if not using "managed"
endpoint: "https://api.nsone.net/v1/"
ignoreSSL: false
example.com
from the staging issuer, default namespace should be fine:apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example.com
spec:
commonName: example.com
dnsNames:
- example.com
issuerRef:
name: letsencrypt-staging
secretName: example-com-tls
After a minute or two, the Certificate
should show as Ready
. If not, you
can follow the resource chain from Certificate
to CertificateRequest
and on
down until you see a useful error message.
See cert-manager docs on "ingress shims".
The gist of it is adding an annotation, and a tls
section to your Ingress
definition. A simple ingress example is below with pertinent areas bolded. We
use the ingress-nginx
ingress controller, but it should be the same idea for
any ingress.
You do of course, need to set up an A
Record in NS1
connecting the domain
to the external IP of the ingress controller's LoadBalancer service. In the
example below the domain would be my-app.example.com
.
apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: my-ingress annotations: kubernetes.io/ingress.class: "nginx" cert-manager.io/cluster-issuer: "letsencrypt-prod" # sets the issuer to use spec: rules: - host: my-app.example.com http: paths: - backend: serviceName: my-app-service servicePort: 80 tls: - hosts: - my-app.example.com # domain name(s) for the certificate secretName: my-app-tls # where to store the secret
If things aren't working, check the logs in the main cert-manager
pod first,
they are pretty communicative. Check logs from the other cert-manager-*
pods
and the cert-manager-webhook-ns1
pod.
If you've generated a Certificate
but no CertificateRequest
is generated,
the main cert-manager
pod logs should show why any action was skipped.
Since this project is essentially a plugin to cert-manager
, detailed docs
mainly live in the cert-manager
project. Here are some specific docs that may
be helpful:
All DNS providers must run the DNS01 provider conformance testing suite, else they will have undetermined behaviour when used with cert-manager.
It is essential that you configure and run the test suite when creating or modifying a DNS01 webhook.
The tests are "live" and require a functioning, DNS-accessible zone, as well as credentials for the NS1 API. The tests will create (and remove) a TXT record for the test zone.
fetch-test-binaries
script:$ scripts/fetch-test-binaries.sh
See the README
in testdata/ns1
and copy/edit the files as needed.
Run the tests with TEST_ZONE_NAME
set to your live, NS1-controlled zone:
$ TEST_ZONE_NAME=example.com. go test .
See Makefile
for commands to build and push the Docker image, and to maintain
the Helm repo.
Pull Requests and issues are welcome. See the NS1 Contribution Guidelines for more information.