GithubHelp home page GithubHelp logo

canonical / tls-certificates-operator Goto Github PK

View Code? Open in Web Editor NEW
2.0 4.0 11.0 491 KB

A charmed operator for managing TLS certificates manually.

Home Page: https://charmhub.io/manual-tls-certificates

License: Apache License 2.0

Python 100.00%
juju tls x509

tls-certificates-operator's Introduction

Manual TLS Certificates

CharmHub Badge

This charm is used to provide X.509 certificates in environments where certificates are obtained through a manual process.

Usage

Deploy the charm and integrate it to a certificate requirer:

juju deploy manual-tls-certificates --channel beta
juju integrate manual-tls-certificates <TLS Certificates Requirer>

Providing X.509 certificates to requesting units

The following Juju actions make it possible for the user to manually provide certificates to units of the requirer charm. If the optional parameter relation-id is provided then only the information of the specified relation is returned.

The following action will return all certificate requests that don't have certificates already provided, along with further information (relation-id, application_name and unit_name)

NOTE: If you happen to scale manual-tls-certificates, you must run actions on the leader unit. However, there is currently no benefit to scaling this charm.

juju run manual-tls-certificates/leader get-outstanding-certificate-requests relation-id=<id>

The second action allows the user to provide the certificates and specify the csr.

juju run manual-tls-certificates/leader provide-certificate \
  relation-id=<id> \
  certificate="$(base64 -w0 certificate.pem)" \
  ca-chain="$(base64 -w0 ca-chain.pem)" \
  ca-certificate="$(base64 -w0 ca-certificate.pem)" \
  certificate-signing-request="$(base64 -w0 csr.pem)" \

Integrations

This charm provides certificates using the tls-certificates integration.

tls-certificates-operator's People

Contributors

danielarndt avatar dariofaccin avatar dependabot[bot] avatar deusebio avatar ghislainbourgeois avatar gruyaume avatar hemanthnakkina avatar jnsgruk avatar kayra1 avatar marcoppenheimer avatar mehdi-bendriss avatar patriciareinoso avatar renovate[bot] avatar saltiyazan avatar telcobot avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

tls-certificates-operator's Issues

[BUG] Error: version `GLIBC_2.33' not found on juju hook "install"

Describe the bug
Impossible to install the latest operator from edge channel.

To Reproduce
Steps to reproduce the behavior:

  1. juju deploy tls-certificates-operator --channel edge --config generate-self-signed-certificates=true --config ca-common-name="My CA"
  2. Wait for error on juju "install" hook
me@juju1:~$ juju status
Model     Controller   Cloud/Region        Version  SLA          Timestamp
microk8s  my-microk8s  microk8s/localhost  2.9.37   unsupported  11:08:55Z

App                        Version  Status   Scale  Charm                      Channel  Rev  Address        Exposed  Message
tls-certificates-operator           waiting      1  tls-certificates-operator  edge      18  10.152.183.84  no       installing agent

Unit                          Workload  Agent  Address      Ports  Message
tls-certificates-operator/0*  error     idle   10.1.47.201         hook failed: "install"

Actual results
Error:

unit-tls-certificates-operator-0: 11:08:32 INFO juju.worker.uniter awaiting error resolution for "install" hook
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install Traceback (most recent call last):
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install   File "./src/charm.py", line 18, in <module>
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install     from charms.tls_certificates_interface.v1.tls_certificates import (  # type: ignore[import]
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install   File "/var/lib/juju/agents/unit-tls-certificates-operator-0/charm/lib/charms/tls_certificates_interface/v1/tls_certificates.py", line 256, in <module>
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install     from cryptography import x509
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install   File "/var/lib/juju/agents/unit-tls-certificates-operator-0/charm/venv/cryptography/x509/__init__.py", line 6, in <module>
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install     from cryptography.x509 import certificate_transparency
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install   File "/var/lib/juju/agents/unit-tls-certificates-operator-0/charm/venv/cryptography/x509/certificate_transparency.py", line 10, in <module>
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install     from cryptography.hazmat.bindings._rust import x509 as rust_x509
unit-tls-certificates-operator-0: 11:08:33 WARNING unit.tls-certificates-operator/0.install ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /var/lib/juju/agents/unit-tls-certificates-operator-0/charm/venv/cryptography/hazmat/bindings/_rust.abi3.so)
unit-tls-certificates-operator-0: 11:08:33 ERROR juju.worker.uniter.operation hook "install" (via hook dispatching script: dispatch) failed: exit status 1

Expected behavior
No errors.

Environment

  • tls-certificates-operator revision 18 (the latest from edge channel)
  • Juju version: 2.9.37 (the latest in 2.9)
  • Cloud Environment: MicroK8s v1.25.4 revision 4221

Additional context
Most probably, something has been recently updated and requires polishing.

provide-certificate action fails to find the relation for the CSR

Describe the bug

This command fails:

juju run -m spark-model manual-tls-certificates/leader provide-certificate certificate="$(cat 10.0.10.186.pem | base64)" ca-certificate="$(cat .local/share/mkcert/rootCA.pem | base64)" certificate-signing-request="$(cat shs.csr | base64)"

As does this

juju run -m spark-model manual-tls-certificates/leader provide-certificate certificate="$(cat 10.0.10.186.pem | base64)" ca-certificate="$(cat .local/share/mkcert/rootCA.pem | base64)" certificate-signing-request="$(cat shs.csr | base64)" relation-id=8

They both give the same error:

Action id 82 failed: Requested relation id is not the correct id of any found CSR's.

In the case of the second command, I got the relation ID from juju show-unit traefik-k8s/0 -m spark-model.

I processed the CSR as:

juju run -m spark-model manual-tls-certificates/leader get-outstanding-certificate-requests
# copied and pasted the output
echo "-----BEGIN CERTIFICATE REQUEST-----\n<REDACTED>\n-----END
  CERTIFICATE REQUEST-----" > shs.csr

Note that the output of get-outstanding-certificate-requests has a rogue line break in END CERTIFICATE REQUEST which I had to manually edit and remove.

I used mkcert to create the certificate:

mkcert -csr shs.csr

Upgrade to Jammy 22.04

I have seen that the charm is based on focal (20.04). Maybe it is worth updating the environment we run on/build on to jammy

CSR secrets are never deleted on relation-broken

Bug Description

Issue

Removing and recreating a certificates relation multiple times leaves behind all the Juju Secrets for the previous CSRs.

I believed the old ones should be cleaned up by the requirer charm.

A mechanism for deleting the secret is already in place here.

To Reproduce

juju deploy self-signed-certificates --channel=latest/edge ca
juju deploy prometheus-k8s --channel=latest/edge prometheus
# Run the following a few times
juju relate prometheus ca
juju remove-relation prometheus ca
juju secrets  # notice the amount of secrets grow indefinitely

Environment

latest/edge for both charms:

  • self-signed-certificates: rev155
  • prometheus-k8s: rev209

Relevant log output

-

Additional context

No response

The consumer side of the relation holds the private key in state

Describe the bug

When running juju show-unit traefik-k8s/0 on a traefik charm integrated with manual-tls-certificates-operator, I noticed that there's a field private_key on the peers relation which contains the private key material related to the CSR that the unit has outstanding. This seems like too much information to me - the private key shouldn't be on display like this in an unprotected form.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.github/workflows/codeql-analysis.yml
  • actions/checkout v4
  • github/codeql-action v3
  • github/codeql-action v3
  • github/codeql-action v3
.github/workflows/issues.yaml
.github/workflows/lint-pr.yaml
  • amannn/action-semantic-pull-request v5
.github/workflows/main.yml
  • actions/checkout v4
  • actions/checkout v4
  • actions/checkout v4
  • actions/checkout v4
  • actions/upload-artifact v4
  • actions/upload-artifact v4
  • actions/upload-artifact v4
  • actions/checkout v4
  • actions/download-artifact v4
  • canonical/charming-actions 2.4.0
  • canonical/charming-actions 2.4.0
  • ubuntu 22.04
  • ubuntu 22.04
  • ubuntu 22.04
  • ubuntu 22.04
  • ubuntu 22.04
.github/workflows/promote.yaml
  • actions/checkout v4
  • canonical/charming-actions 2.4.0
.github/workflows/update-libs.yaml
  • actions/checkout v4
  • peter-evans/create-pull-request v5.0.2
pip_requirements
requirements.txt
  • attrs ==23.2.0
  • cffi ==1.16.0
  • cryptography ==41.0.7
  • jsonschema ==4.21.0
  • jsonschema-specifications ==2023.12.1
  • ops ==2.9.0
  • pycparser ==2.21
  • pyyaml ==6.0.1
  • referencing ==0.32.1
  • rpds-py ==0.17.1
  • websocket-client ==1.7.0
test-requirements.txt
  • asttokens ==2.4.1
  • bcrypt ==4.1.2
  • black ==23.12.1
  • cachetools ==5.3.2
  • certifi ==2023.11.17
  • cffi ==1.16.0
  • charset-normalizer ==3.3.2
  • click ==8.1.7
  • coverage ==7.4.0
  • cryptography ==41.0.7
  • decorator ==5.1.1
  • executing ==2.0.1
  • flake8 ==6.1.0
  • flake8-builtins ==2.2.0
  • flake8-copyright ==0.2.4
  • flake8-docstrings ==1.7.0
  • google-auth ==2.26.2
  • hvac ==2.1.0
  • idna ==3.6
  • iniconfig ==2.0.0
  • ipdb ==0.13.13
  • ipython ==8.20.0
  • isort ==5.13.2
  • jedi ==0.19.1
  • jinja2 ==3.1.3
  • juju ==3.3.0.0
  • kubernetes ==29.0.0
  • macaroonbakery ==1.3.4
  • markupsafe ==2.1.3
  • matplotlib-inline ==0.1.6
  • mccabe ==0.7.0
  • mypy ==1.8.0
  • mypy-extensions ==1.0.0
  • oauthlib ==3.2.2
  • ops ==2.9.0
  • ops-scenario ==6.0
  • packaging ==23.2
  • paramiko ==2.12.0
  • parso ==0.8.3
  • pathspec ==0.12.1
  • pep8-naming ==0.13.3
  • pexpect ==4.9.0
  • platformdirs ==4.1.0
  • pluggy ==1.3.0
  • prompt-toolkit ==3.0.43
  • protobuf ==4.25.2
  • ptyprocess ==0.7.0
  • pure-eval ==0.2.2
  • pyasn1 ==0.5.1
  • pyasn1-modules ==0.3.0
  • pycodestyle ==2.11.1
  • pycparser ==2.21
  • pydantic ==1.10.13
  • pydocstyle ==6.3.0
  • pyflakes ==3.1.0
  • pygments ==2.17.2
  • pymacaroons ==0.13.0
  • pynacl ==1.5.0
  • pyproject-flake8 ==6.1.0
  • pyrfc3339 ==1.1
  • pytest ==7.4.4
  • pytest-asyncio ==0.21.1
  • pytest-interface-tester ==1.0.7
  • pytest-operator ==0.32.0
  • python-dateutil ==2.8.2
  • pytz ==2023.3.post1
  • pyyaml ==6.0.1
  • requests ==2.31.0
  • requests-oauthlib ==1.3.1
  • rsa ==4.9
  • six ==1.16.0
  • snowballstemmer ==2.2.0
  • stack-data ==0.6.3
  • toposort ==1.10
  • traitlets ==5.14.1
  • typer ==0.7.0
  • types-pyyaml ==6.0.12.12
  • types-setuptools ==69.0.0.20240115
  • types-toml ==0.10.8.7
  • typing-extensions ==4.9.0
  • typing-inspect ==0.9.0
  • urllib3 ==2.1.0
  • wcwidth ==0.2.13
  • websocket-client ==1.7.0
  • websockets ==12.0

  • Check this box to trigger a request for Renovate to run again on this repository

`get-outstanding-certificate-requests` return value is a Python literal string

Describe the bug

Value stored in the result of the get-outstanding-certificate-requests action is a python literal as a string. This requires the ability to parse the string as Python to programmatically make use of the data.

Using a Python literal string isn't a common format for communicating data. Something like JSON would be a much better fit.

To Reproduce

juju deploy tls-certificates-requirer --channel edge
juju deploy tls-certificates-operator --channel edge
juju integrate tls-certificates-operator tls-certificates-requirer
juju run tls-certificates-operator/0 get-outstanding-certificate-requests --format=json 2>/dev/null | jq '."tls-certificates-operator/0".results.result'

Result is

[{'relation_id': 0, 'application_name': 'tls-certificates-requirer', 'unit_name': 'tls-certificates-requirer/0', 'unit_csrs': [{'certificate_signing_request': '-----BEGIN CERTIFICATE REQUEST-----<content>-----END CERTIFICATE REQUEST-----'}]}]"

which looks like JSON, but it isn't

juju run tls-certificates-operator/0 get-outstanding-certificate-requests --format=json 2>/dev/null | jq '."tls-certificates-operator/0".results.result | fromjson' # Get the result, parse it as JSON

The above throws an error.

Expected behavior

Expected a common format for the result output.

This data should likely be in JSON format, since the certificates data is already in JSON.

Environment

  • charm version: 50

Add a hook to notify the clients that there is a CA rotation

Enhancement Proposal

Currently, there is no way to notify the clients of the manual-tls-certificates operator that there is a CA rotation taking place.
A hook to notify the clients that a CA rotation is taking place should be added to trigger the rotation on the client side and request new CSRs.

[RFE] operator should validate the received certificate and CA chain against each other

Where the change should be applied: tls-certificate-operator code (not its lib)

At provide-certificate action, the current implementation of tls-certificates-operator only validate the certificate itself and each certificate composing the CA chain. However, it does not check if the certificate chain is valid

For that, we should extend this part of the action to support verify_directly_issued_by method.

If that validation fails, then the action should return an error.

[RFE] Accept third-party CAs to be trusted by all related units

There are two very common scenarios where we need to inject third party CAs on all units at once:

  1. SSLBump proxy: a proxy acts as a MITM and generates certificates using its own CA to sign off for each HTTPS connection
  2. mTLS support: we may need to add extra CAs from other PKIs to be trusted for a mTLS connection

These CAs should be managed the same way as the other CAs (i.e. generating events and alerts if one of the CAs will expire)

cert expiration monitoring

Enhancement Proposal

As a centralized charm for managing certificates, I think manual-tls-certificates should also provide observability over the lifetime of the certificates it provides. This could for example be a metric indicating the time left until expiration, plus an alert rule firing 30 days prior to it.

As an MSP, a (legacy) equivalent setup - part of openstack-service-checks - has been crucial for us in order to get the ball rolling in time for certificate renewals in Charmed OpenStack clouds. As modern environments rely on charms like this one for managing certificates, it is important to be able to provide similar functionality (but integrated with COS).

[BUG] Test issue, the issue is for testing purposes and will be deleted - please ignore

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Logs
If applicable, add logs to help explain your problem.

Environment

  • tls-certificates-interface library version [e.g. 1.2]
  • Juju version: [e.g. 2.9.23]
  • Cloud Environment [e.g. GKE]
  • Kubernetes version [e.g. 1.22]

Additional context
Add any other context about the problem here.

ca-common-name is not support in rev 50 from latest/edge

Describe the bug

SolQA tried to deplot tls-certificates-operator rev 50 from latest/edge channel with kafka,
but end up failed because "ca-common-name" is not supported.

To Reproduce

$ juju deploy tls-certificates-operator --channel edge --config generate-self-signed-certificates="true" --config ca-common-name="10"
ERROR unknown option "ca-common-name"
ERROR failed to deploy charm "tls-certificates-operator"

$ juju deploy tls-certificates-operator --channel stable --config generate-self-signed-certificates="true" --config ca-common-name="10"
Deployed "tls-certificates-operator" from charm-hub charm "tls-certificates-operator", revision 22 in channel stable on [email protected]/stable

Expected behavior

This should work as stable channel.

Screenshots

Logs

2023-12-16-16:10:15 root DEBUG - upload charm tls-certificates-operator from charm-hub for base [email protected]/stable from channel latest/edge with architecture=amd64
2023-12-16-16:10:15 root DEBUG 16:10:15 INFO juju.cmd.juju.application.deployer baseselector.go:121 with the user specified base "[email protected]/stable"
2023-12-16-16:10:15 root DEBUG 16:10:15 INFO juju.cmd.juju.application.deployer baseselector.go:200 with the user specified base "[email protected]/stable"
2023-12-16-16:10:15 root DEBUG 16:10:15 DEBUG juju.cmd.juju.application.deployer bundlehandler.go:690 added charm ch:amd64/jammy/tls-certificates-operator-50 for channel latest/edge
2023-12-16-16:10:15 root DEBUG 16:10:15 DEBUG juju.cmd.juju.application.deployer bundlehandler.go:1662 resolve "$addCharm-6" from map[string]string{"addCharm-0":"ch:amd64/jammy/kafka-146", "addCharm-2":"ch:amd64/jammy/grafana-agent-28", "addCharm-4":"ch:amd64/jammy/ntp-50", "addCharm-6":"ch:amd64/jammy/tls-certificates-operator-50", "deploy-1":"kafka", "deploy-3":"kafka-agent", "deploy-5":"ntp"}
2023-12-16-16:10:15 root DEBUG - deploy application tls-certificates-operator from charm-hub on [email protected]/stable with latest/edge
2023-12-16-16:10:15 root DEBUG 16:10:15 DEBUG juju.api monitor.go:35 RPC connection died
2023-12-16-16:10:15 root DEBUG 16:10:15 DEBUG juju.api monitor.go:35 RPC connection died
2023-12-16-16:10:15 root DEBUG ERROR cannot deploy bundle: cannot deploy application "tls-certificates-operator": unknown option "ca-common-name"
2023-12-16-16:10:15 root DEBUG 16:10:15 DEBUG cmd supercommand.go:549 error stack:
2023-12-16-16:10:15 root DEBUG unknown option "ca-common-name"
2023-12-16-16:10:15 root DEBUG github.com/juju/juju/api/client/application.(*Client).Deploy:178:
2023-12-16-16:10:15 root DEBUG github.com/juju/juju/cmd/juju/application.(*deployAPIAdapter).Deploy:93:
2023-12-16-16:10:15 root DEBUG github.com/juju/juju/cmd/juju/application/deployer.(*bundleHandler).addApplication:918: cannot deploy application "tls-certificates-operator"
2023-12-16-16:10:15 root DEBUG github.com/juju/juju/cmd/juju/application/deployer.(*bundleHandler).handleChanges:561:
2023-12-16-16:10:15 root DEBUG github.com/juju/juju/cmd/juju/application/deployer.bundleDeploy:100:
2023-12-16-16:10:15 root DEBUG github.com/juju/juju/cmd/juju/application/deployer.(*deployBundle).deploy:117: cannot deploy bundle
2023-12-16-16:10:15 root ERROR [localhost] Command failed: juju deploy -m foundations-maas:kafka --debug /home/ubuntu/project/generated/kafka/bundle.yaml
2023-12-16-16:10:15 root ERROR 1[localhost] STDOUT follows:
Executing changes:

  • upload charm kafka from charm-hub for base [email protected]/stable from channel 3/edge with architecture=amd64
  • deploy application kafka from charm-hub on [email protected]/stable with 3/edge
  • upload charm grafana-agent from charm-hub for base [email protected]/stable from channel latest/edge with architecture=amd64
  • deploy application kafka-agent from charm-hub on [email protected]/stable with latest/edge using grafana-agent
  • upload charm ntp from charm-hub for base [email protected]/stable from channel latest/edge with architecture=amd64
  • deploy application ntp from charm-hub on [email protected]/stable with latest/edge
  • upload charm tls-certificates-operator from charm-hub for base [email protected]/stable from channel latest/edge with architecture=amd64
  • deploy application tls-certificates-operator from charm-hub on [email protected]/stable with latest/edge

Environment

  • tls-certificates-interface library version:
  • Juju version (output from juju --version): 3.3.0
  • Cloud Environment: MAAS
  • Kubernetes version (output from kubectl version --short):

Additional context

This is from SolQA test run - https://solutions.qa.canonical.com/testruns/b0bd64d2-b148-4e7c-a392-2e149dd6fe3a
All artifacts can be found here - https://oil-jenkins.canonical.com/artifacts/b0bd64d2-b148-4e7c-a392-2e149dd6fe3a/index.html

[BUG] CertificateAvailable event is being triggered for units that already received it

Describe the bug

Given the scenario: 3 unit app A related to tls-certs charm and all is fine.
The on.certificate_available handle on app A test it own csr against the incoming event csr and being it the same, enable TLS for the workload queuing it to a rolling restart.

The issue appears when one or more units are added to app A.
For each new unit added, the existing units are going to receive a CertificateAvailable event, with a valid csr per unit, triggering an unnecessary workload restart.

To Reproduce
Steps to reproduce the behavior:

  1. deploy tls-certificates-operator and mysql-k8s
  2. relate applications and wait for idle
  3. scale up mysql-k8s by n units
  4. observe CertificateAvailable being triggered for the units deployed before the scale out

Expected behavior
Only new n units should receive CertificateAvailable event.

Environment

  • tls-certificates-interface library version: 1.12
  • Juju version: 2.9.38
  • Cloud Environment: localhost
  • Kubernetes version: microk8s 1.26.1

Deprecation warning: please switch to not_valid_after_utc

Hi team,

Seems that we are using an outdated way to work with datetime, and I am seeing these in the logs:

/charm/lib/charms/tls_certificates_interface/v3/tls_certificates.py:682: CryptographyDeprecationWarning: Properties that return a naïve datetime object have been deprecated. Please switch to not_valid_after_utc.

`provide certificate` action requires `relation-id`, which is non-trivial to find

Describe the bug

The provide-certificate action mandates that the relation-id is provided along with the signed cert. However this is not a particularly obvious thing to find. It requires running juju show-unit <unit> and grokking through a ton of YAML.

My suggestion is to drop this requirement and either infer the relation from the subject name of the provided signed certificate - or only allow a 1:1 relation between the manual-tls-operator and other charm.

Providing a letsencrypr certificate results in AttributeError: 'cryptography.hazmat.primitives.asymmetric.ec.Ellip' object has no attribute 'n'

Bug Description

provide-certificate results in error with AttributeError: 'cryptography.hazmat.primitives.asymmetric.ec.Ellip' object has no attribute 'n'

To Reproduce

juju deploy manual-tls-certificates --channel latest/edge
juju relate istio-pilot manual-tls-certificates
juju run manual-tls-certificates/leader provide-certificate relation-id=65 certificate="$(base64 -w0 certificate.pem)" ca-certificate="$(base64 -w0 ca-certificate.pem)" certificate-signing-request="$(base64 -w0 csr.pem)"

Environment

Juju 3.4.3
Kubernetes AKS/Azure 1.28.9
Charm revision:
manual-tls-certificates active 1 manual-tls-certificates latest/edge 105 10.0.188.149 no 1 outstanding requests, use juju actions to provide certificates

Relevant log output

unit-manual-tls-certificates-0: 11:25:37 ERROR unit.manual-tls-certificates/0.juju-log Uncaught exception while in charm code:
Traceback (most recent call last):
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/./src/charm.py", line 270, in <module>
    main(ManualTLSCertificatesCharm)
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/main.py", line 548, in main
    manager.run()
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/main.py", line 527, in run
    self._emit()
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/main.py", line 516, in _emit
    _emit_charm_event(self.charm, self.dispatcher.event_name)
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/main.py", line 147, in _emit_charm_event
    event_to_emit.emit(*args, **kwargs)
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/framework.py", line 348, in emit
    framework._emit(event)
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/framework.py", line 860, in _emit
    self._reemit(event_path)
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/venv/ops/framework.py", line 950, in _reemit
    custom_handler(event)
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/lib/charms/tempo_k8s/v1/charm_tracing.py", line 546, in wrapped_function
    return callable(*args, **kwargs)  # type: ignore
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/./src/charm.py", line 137, in _on_provide_certificate_action
    if not csr_matches_certificate(csr=csr, cert=certificate):
  File "/var/lib/juju/agents/unit-manual-tls-certificates-0/charm/lib/charms/tls_certificates_interface/v3/tls_certificates.py", line 1125, in csr_matches_certificate
    csr_object.public_key().public_numbers().n  # type: ignore[union-attr]
AttributeError: 'cryptography.hazmat.primitives.asymmetric.ec.Ellip' object has no attribute 'n'
unit-manual-tls-certificates-0: 11:25:37 WARNING unit.manual-tls-certificates/0.provide-certificate Uncaught AttributeError in charm code: 'cryptography.hazmat.primitives.asymmetric.ec.Ellip' object has no attribute 'n'
unit-manual-tls-certificates-0: 11:25:37 WARNING unit.manual-tls-certificates/0.provide-certificate Use `juju debug-log` to see the full traceback.

Additional context

No response

[RFE] tls-certificates-operator should have default integration with COS

Certificate management demands a continuous monitoring of all the certificates provided. The operator should have an integration with COS alertmanager and provide the following alerts:

  • per certificate (incl. CAs): WARN if certificate is expiring
  • per certificate (incl. CAs): CRIT if certificate was invalidated or expired and no replacement presented

[RFE] At provide-certificate action, verify public keys in CSR and received certificate matches

During the processing of provide-certificate action, the tls-certificates-operator should use the relation-id provided as a parameter to recover the CSR set by the Requirer and compare main fields:

# Compare types as there are multiple and key values
if not csr.public_key === certificate.public_key:
    event.fail(message="Certificate and CSR public keys do not match")
    return
if csr.subject != certificate.subject:
    event.fail(message=f"Certificate has subject: {certificate.subject} whereas CSR has: {csr.subject}")
    return

[BUG] Failure to deploy operator with multiple units

Steps to reproduce

Deployed TLS operator related to multiple applications:

tls:certificates     consumer:certificates   tls-certificates          regular  
tls:certificates     kafka:certificates      tls-certificates          regular  
tls:certificates     producer:certificates   tls-certificates          regular  
tls:certificates     zookeeper:certificates  tls-certificates          regular  
tls:replicas         tls:replicas            tls-certificates-replica  peer     

juju add-unit tls -n 3

Error Logs

Traceback (most recent call last):
  File "/var/lib/juju/agents/unit-tls-1/charm/./src/charm.py", line 514, in <module>
    main(TLSCertificatesOperatorCharm)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/main.py", line 431, in main
    _emit_charm_event(charm, dispatcher.event_name)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/main.py", line 142, in _emit_charm_event
    event_to_emit.emit(*args, **kwargs)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/framework.py", line 316, in emit
    framework._emit(event)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/framework.py", line 784, in _emit
    self._reemit(event_path)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/framework.py", line 857, in _reemit
    custom_handler(event)
  File "/var/lib/juju/agents/unit-tls-1/charm/lib/charms/tls_certificates_interface/v1/tls_certificates.py", line 1039, in _on_relation_changed
    provider_relation_data = _load_relation_data(event.relation.data[self.charm.app])
  File "/var/lib/juju/agents/unit-tls-1/charm/lib/charms/tls_certificates_interface/v1/tls_certificates.py", line 565, in _load_relation_data
    for key in raw_relation_data:
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/model.py", line 545, in __iter__
    return iter(self._data)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/model.py", line 532, in _data
    data = self._lazy_data = self._load()
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/model.py", line 920, in _load
    return self._backend.relation_get(self.relation.id, self._entity.name, self._is_app)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/model.py", line 2131, in relation_get
    raw_data_content = self._run(*args, return_output=True, use_json=True)
  File "/var/lib/juju/agents/unit-tls-1/charm/venv/ops/model.py", line 2052, in _run
    raise ModelError(e.stderr)
ops.model.ModelError: b'ERROR permission denied\n'

Also, not sure if it's helpful, but getting the following error from the related units:

    def _request_certificate(self):
        """Generates and submits CSR to provider."""
        csr = generate_csr(
            private_key=self.private_key.encode("utf-8"),
            subject=self.peer_relation.data[self.charm.unit].get("private-address", ""),
            **self._sans,
        )
        self.charm.set_secret(scope="unit", key="csr", value=csr.decode("utf-8").strip())  # <--- sets 'self.csr'
        self.certificates.request_certificate_creation(certificate_signing_request=csr)


    def _on_certificate_available(self, event: CertificateAvailableEvent) -> None:
        """Handler for `certificates_available` event after provider updates signed certs."""
        # avoid setting tls files and restarting
        if event.certificate_signing_request != self.csr:
            logger.error("Can't use certificate, found unknown CSR")  # <--- this is being called on all units
            return
unit-kafka-0: 20:01:28 ERROR unit.kafka/0.juju-log certificates:8: Can't use certificate, found unknown CSR
unit-kafka-0: 20:01:28 ERROR unit.kafka/0.juju-log certificates:8: Can't use certificate, found unknown CSR
unit-kafka-0: 20:01:28 ERROR unit.kafka/0.juju-log certificates:8: Can't use certificate, found unknown CSR
unit-zookeeper-2: 20:01:28 ERROR unit.zookeeper/2.juju-log certificates:7: Can't use certificate, found unknown CSR
unit-zookeeper-2: 20:01:28 ERROR unit.zookeeper/2.juju-log certificates:7: Can't use certificate, found unknown CSR
unit-zookeeper-2: 20:01:28 ERROR unit.zookeeper/2.juju-log certificates:7: Can't use certificate, found unknown CSR
unit-kafka-0: 20:01:29 ERROR unit.kafka/0.juju-log certificates:8: Can't use certificate, found unknown CSR
unit-kafka-0: 20:01:29 ERROR unit.kafka/0.juju-log certificates:8: Can't use certificate, found unknown CSR
unit-kafka-0: 20:01:29 ERROR unit.kafka/0.juju-log certificates:8: Can't use certificate, found unknown CSR

[BUG] The SANs are not set on the generated certificates

Describe the bug
The SANs do not get propagated to the generated certificate.

To Reproduce

def _get_sans() -> List[str]:
    unit_id = self.charm.unit.name.split("/")[1]
    return [
        f"{self.charm.app.name}-{unit_id}",
        socket.getfqdn(),
        get_host_ip(self.charm, self.peer_relation),
    ]

csr = generate_csr(
    add_unique_id_to_subject_name=False,
    private_key=key,
    private_key_password=password,
    subject=subject,
    organization=self.charm.app.name,
    sans=self._get_sans(),
    oid="1.2.3.4.5.5",
)

Because of a requirement to set the OID on the SAN, I had to locally alter a bit the generate_csr function in the TLS library to allow for setting of the oid as follows:

_sans = []
if oid:
    _sans.append(x509.RegisteredID(x509.ObjectIdentifier(oid)))
if sans:
    _sans.extend([x509.DNSName(san) for san in sans])

if _sans:
    csr = csr.add_extension(
        x509.SubjectAlternativeName(_sans), critical=True
    )

Expected behavior

  • The CSR should contain the 4 SANs
  • The generated certificate should also contain

Screenshots
The extensions part of the CSR

Requested Extensions:
    X509v3 Subject Alternative Name: critical
        Registered ID:1.2.3.4.5.5

And on the cert side:

openssl x509 -ext subjectAltName -in unit.cert -text`
No extensions in certificate
....

Environment

  • tls-certificates-interface library version [e.g. 1.2]
  • Juju version: 2.9.34
  • Cloud Environment: LXD

[BUG] spelling typos in shared library triggers lint error

Describe the bug

Our codespell lint is not happy after updating to TLS library to LIBPATCH 12:

.../tls_certificates_interface/v1/tls_certificates.py:1025: triggerred ==> triggered
.../tls_certificates_interface/v1/tls_certificates.py:1068: agains ==> against, again

Can you please fix typos? Maybe consider to add codespell to your lint. Thank you!

Certificate and CSR do not match when trying to provide signed certificate

Describe the bug

I got a certificate signed by IS based on the CSR using Digicert, I have the following failure: "Certificate and CSR do not match." when running the provide action

To Reproduce

Run:
juju run-action stg-tls-certificate/leader provide-certificate relation-id=32 certificate="$(base64 -w0 certificate.pem)" ca-chain="$(base64 -w0 ca-chain.pem)" ca-certificate="$(base64 -w0 ca-certificate.pem)" certificate-signing-request="$(base64 -w0 csr.pem)"
With a certificate signed by DigiCert from a CSR generated by the charm

Expected behavior

Certificate is accepted

Environment

  • Certificate signed by DigiCert provided by IS

Additional context

I'm pretty sure the issue comes from here:
https://github.com/canonical/manual-tls-certificates-operator/blob/main/lib/charms/tls_certificates_interface/v2/tls_certificates.py#L1688-L1689

Basically the subject on the CSR and certificates differs because the CSR doesn't any Country, Location and Organisation, and the signing authorities always add them to the signed certificates
The CSR has:
Subject: CN = iam.identity.staging.canonical.com, x500UniqueIdentifier = 61bb6883-458b-4515-9a80-2da6c786eb37
And certificate has:
Subject: C = GB, L = London, O = CANONICAL GROUP LIMITED, CN = iam.identity.staging.canonical.com
That can't work 😕
I checked that the CSR and the certificates matches by checking the modulus which is I think a good way

ca-chain attribute should be optional

Describe the bug

At the moment, the ca-chain attribute of the provide-certificate action is mandatory, and requires at least two certificates to be provided. This makes no sense when a private CA service is in play, and makes the charm unusable, since the chain is only the single root cert, which is already provided in the ca-certificate atribute.

[BUG]Action parameters may be broken

Describe the bug
The charm does not have good parameters for its actions. When trying to execute an action, there is an error in validation because the parameter have underscores in their names (e.g. relation_id) and that throws an error.

To Reproduce
Steps to reproduce the behavior:
1- Execute any action with a parameter that contains an underscore. E.g. juju run tls-certificates-operator/0 get-outstanding-certificate-requests relation_id=0

Expected behavior
The action should execute without any errors.

Screenshots
image

Environment

  • tls-certificates-interface library version 2.12
  • Juju version: 3.1.5-genericlinux-amd64
  • Cloud Environment: Microk8s cloud
  • Kubernetes version 1.28

Add a `certificate_transfer` relation

Enhancement Proposal

Currently, the charm only has a tls-certificates relation.
Some use cases would benefit certificates_transfer support, for example when grafana tries to reach loki over its ingress url.

graph LR
custom-cert -.- traefik --- grafana --- manual-tls-cert
traefik --- loki --- manual-tls-cert
grafana --- loki
Loading

Charm should have the option to provide externally issued certificates

Enhancement Proposal

Right now if you provide a certificate from, let's say letsencrypt, you can't use it as you can't obtain the CSR. It would be nice to have an action that will take the certificate, key, ca-certificate and assign it to a relation id, overriding the issued CSR by the charm.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.