ncm-issuer is a Kubernetes controller (external cert-manager issuer) that allows to integrate with Nokia NetGuard Certificate Manager (NCM) PKI system to sign certificate requests. The integration with NCM makes it easy to obtain non-selfsigned certificates for applications and to ensure that they are valid and up to date.
- Prerequisites
- Installation and configuration
- Custom resource definitions (CRDs)
- Usage
- Troubleshooting
Prerequisites for building and using ncm-issuer:
- NCM release 21 or later,
- Kubernetes version 1.24 - 1.29,
- cert-manager version 1.0.0 or later,
- Docker version 20.10.0 or later,
- Helm v3.
The easiest way to install ncm-issuer in Kubernetes cluster is to use Helm. The image will be automatically downloaded from public repository.
Install ncm-issuer using the command:
$ helm install \
ncm-issuer \
--create-namespace --namespace ncm-issuer \
helm
On the other hand, if you did not use git
, but downloaded the packaged version of ncm-issuer use:
$ helm install \
ncm-issuer \
--create-namespace --namespace ncm-issuer \
ncm-issuer/charts/ncm-issuer
In case you want to use your own registry, just change the value pointing to a specific registry
in the values.yaml
file in directory that contains Helm files. Then just repeat the steps
mentioned above.
sed -i "s|docker.io/misiektoja|<your-registry>|g" values.yaml
However, if you do not know where to get image from, because you cloned the repository just use the command:
$ make docker-build
or (if you also want to save image)
$ make docker-save
Saved image should appear in the path ./builds/ncm-issuer-images/
.
To make the ncm-issuer work properly, it is necessary to create few Kubernetes secrets that contains credentials to NCM REST API and TLS configuration.
$ kubectl create secret generic \
<secret-name> \
-n <namespace> \
--from-literal=username=<username> \
--from-literal=usrPassword=<password>
$ kubectl create secret generic \
<secret-name> \
-n <namespace> \
--from-file=cacert=<ca-for-tls.pem>
$ kubectl create secret generic \
<secret-name> \
-n <namespace> \
--from-file=cacert=<ca-for-tls.pem> \
--from-file=key=<client-auth-pkey.pem> \
--from-file=cert=<client-auth-cert.pem>
To make sure that specific secret have been created correctly, you can check this by using command:
$ kubectl -n <namespace> describe secrets <secret-name>
Below is an example yaml
file containing Issuer
definition:
apiVersion: certmanager.ncm.nokia.com/v1
kind: Issuer
metadata:
name: example-ncm-issuer
namespace: ncm-ns
spec:
# caName or caID is always required.
caName: ncm-ca
caID: e1DefAscx
provisioner:
# mainAPI is always required.
mainAPI: https://nokia-ncm.local
backupAPI: https://nokia-backup-ncm.local
httpClientTimeout: 10s
healthCheckerInterval: 1m
# authRef is always required.
authRef:
name: ncm-rest-auth
namespace: ncm-ns
tlsRef:
name: ncm-tls
namespace: ncm-ns
profileId: "101"
useProfileIDForRenew: true
reenrollmentOnRenew: true
noRoot: true
chainInSigner: false
onlyEECert: true
1.1.0-1.1.0
the name of some fields in Issuer
has changed, but old names are
still supported and can be used (this applies to: CASNAME
, CASHREF
, ncmSERVER
, ncmSERVER2
, secretName
,
tlsSecretName
, authNameSpace
).
With the ClusterIssuer
, the definition does not differ from that presented
with Issuer
, and the only differences are in the field kind
and the non-existence of field
.metadata.namespace
due to Cluster
scope reasons.
apiVersion: certmanager.ncm.nokia.com/v1
kind: ClusterIssuer
metadata:
name: example-ncm-clusterissuer
spec:
...
Field | Description | Supported from |
---|---|---|
.spec.caName |
Name of an existing CA in the NCM, which will be used to issue certificates (required if .spec.caID is not specified) |
1.1.0-1.1.0 |
.spec.caID |
Unique HREF identifier for existing CA in the NCM, which will be used to issue certificates (required if .spec.caName is not specified) |
1.1.0-1.1.0 |
.spec.provisioner.mainAPI |
The URL to the main NCM REST API (always required) | 1.1.0-1.1.0 |
.spec.provisioner.backupAPI |
The URL to the backup NCM REST API in case of the lack of connection to the main one | 1.1.0-1.1.0 |
.spec.provisioner.httpClientTimeout |
Maximum amount of time that the HTTP client will wait for a response from NCM REST API before aborting the request | 1.1.0-1.1.0 |
.spec.provisioner.healthCheckerInterval |
The time interval between each NCM REST API health check | 1.1.0-1.1.0 |
.spec.provisioner.authRef |
Reference to a Secret containing the credentials (user and password) needed for making requests to NCM REST API (always required) | 1.1.0-1.1.0 |
.spec.provisioner.tlsRef |
Reference to a Secret containing CA bundle used to verify connections to the NCM REST API. If the secret reference is not specified and selected protocol is HTTPS, InsecureSkipVerify will be used. Otherwise, TLS or mTLS connection will be used, depending on provided data | 1.1.0-1.1.0 |
.spec.reenrollmentOnRenew |
Determines whether during renewal, certificate should be re-enrolled instead of renewed | 1.0.1-1.0.0 |
.spec.profileId |
Entity profile ID in NCM, optional; needs to be in double quotes | 1.0.1-1.0.0 |
.spec.noRoot |
Determines whether issuing CA certificate should be included in issued certificate CA field (ca.crt) instead of root CA certificate | 1.0.1-1.0.0 |
.spec.chainInSigner |
Determines whether certificate chain should be included in issued certificate CA field (ca.crt - root CA certificate + intermediate CA certificates + singing CA certificate) | 1.0.3-1.0.2 |
.spec.onlyEECert |
Determines whether only end-entity certificate should be included in issued certificate TLS field (tls.crt) | 1.0.3-1.0.2 |
❌ Deprecated: The following fields are not recommended to be used anymore!
Field | Description | Supported from |
---|---|---|
.spec.CASNAME |
Name of an existing CA in the NCM, which will be used to issue certificates | 1.0.1-1.0.0 |
.spec.CASHREF |
Unique HREF identifier for existing CA in the NCM, which will be used to issue certificates | 1.0.1-1.0.0 |
.spec.ncmSERVER |
The URL to the main NCM REST API | 1.0.1-1.0.0 |
.spec.ncmSERVER2 |
The URL to the backup NCM REST API in case of the lack of connection to the main one | 1.0.3-1.0.2 |
.spec.SecretName |
The name of Secret which contains the credentials (user and password) needed for making requests to NCM REST API | 1.0.1-1.0.0 |
.spec.authNameSpace |
The name of namespace in which Secret to NCM REST API credentials can be found | 1.0.1-1.0.0 |
.spec.tlsSecretName |
The name of Secret which contains CA bundle used to verify connections to the NCM REST API | 1.0.1-1.0.0 |
Once the deployment is up and running, you are ready to create your first Issuer
!
The following is an example Issuer
created for the namespace example-ncm-ns
:
$ cat << EOF | kubectl apply -f -
apiVersion: certmanager.ncm.nokia.com/v1
kind: Issuer
metadata:
name: example-ncm-issuer
namespace: example-ncm-ns
spec:
caName: ncm-ca
provisioner:
mainAPI: https://nokia-ncm.local
authRef:
name: ncm-rest-auth
namespace: example-ncm-ns
EOF
After creating the Issuer
, we should now be able to check its status:
$ kubectl get ncmissuers -n example-ncm-ns
NAME AGE READY REASON MESSAGE
example-ncm-issuer 3s True Verified Signing CA verified and ready to sign certificates
The above output tells us that our Issuer
is ready to sign certificates!
Once the Issuer
was successfully created, it is now time to sign the first certificate:
$ cat << EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-ncm-certificate
namespace: example-ncm-ns
spec:
commonName: example-ncm-certificate-nokia-ncm.local
dnsNames:
- example-ncm-certificate-nokia-ncm.local
subject:
countries:
- PL
organizationalUnits:
- Security
organizations:
- Nokia
usages:
- server auth
- data encipherment
secretName: example-ncm-certificate-nokia-ncm-tls
issuerRef:
group: certmanager.ncm.nokia.com
kind: Issuer
name: example-ncm-issuer
EOF
Then we can check the status of our newly issued certificate:
$ kubectl get certificates -n example-ncm-ns
NAME READY SECRET AGE
example-ncm-certificate True example-ncm-certificate-nokia-ncm-tls 17s
and whether it has corresponding Secret referenced:
$ kubectl get secrets -n example-ncm-ns
NAME TYPE DATA AGE
default-token-g2f47 kubernetes.io/service-account-token 3 18m
example-ncm-certificate-details Opaque 1 22s
example-ncm-certificate-nokia-ncm-tls kubernetes.io/tls 3 22s
Additionally, in NCM GUI we can also find our newly issued certificate.
When it comes to renewing or reenrolling certificates, ncm-issuer will take care of this and
do it before the certificate expires (the renewal grace period
depends on the defined values in Certificate
resource).
You can define what operation ncm-issuer should perform in such a case by
setting certain PK rotation policy in Certificate
resource.
Field | Operation | Value |
---|---|---|
.spec.privateKey.rotationPolicy |
Reenrollment | "Always" |
.spec.privateKey.rotationPolicy |
Renewal | "Never" or not even specified |
📢 Attention: There is also an option for enforcing the reenrollment on
renewal in the definition of Issuer
or ClusterIssuer
resource. To do this simply set .spec.reenrollmentOnRenew
to true in Issuer
or ClusterIssuer
definition.
However, you can also trigger renewal or reenrolling operation manually using one of the commands below.
In case you have cert-manager kubectl plugin:
$ kubectl cert-manager renew <certificate> -n <namespace>
In case you use cmctl:
$ cmctl renew <certificate> -n <namespace>
In case of any problem, besides checking the status of created resources,
you can also check the ncm-issuer
pod logs:
$ kubectl -n ncm-issuer logs -f `kubectl get pods -A -l app=ncm-issuer -o jsonpath='{.items[0].metadata.name}'`
If you deployed troubleshooting sidecar as well, you can check the ncm-issuer
pod logs this way:
$ kubectl -n ncm-issuer logs -c ncm-issuer -f `kubectl get pods -A -l app=ncm-issuer -o jsonpath='{.items[0].metadata.name}'`
In the case you want to increase logging verbosity level, change the logging.logLevel
in values.yaml
to
the desired value and update your deployment. To get all possible log messages, simply set the
logging.logLevel
to 3, you can also additionally change the logging.stacktraceLevel
to
error
.
There is also the possibility of using sidecar for troubleshooting purposes - just change the value of
sidecar.enabled
to true in values.yaml
and update your deployment.