docs: extend security explanation page to cover SEC0030 V1.3 gaps#2571
docs: extend security explanation page to cover SEC0030 V1.3 gaps#2571tonyandrewmeyer wants to merge 3 commits into
Conversation
…3 gaps Extend docs/explanation/security.md to close the SEC0030 V1.3 gaps recorded in the operator gap analysis. This is an extension only; existing sections are unchanged except for the noted Cryptography and Security-lifecycle additions. Added sections: - Product architecture: trust boundaries (Juju, ops, charm code) and what ops controls versus delegates, referencing the existing Inter-process communication and Charm unit databases sections. - Secure by Design: design rationale for the minimal security surface (no network listeners, crypto delegated to Juju and the stdlib, bounded persistence). - Logging and monitoring: charm logging via juju-log through the Python stdlib logging module, with a forward reference to SEC0045 security-event logging. - Secure decommissioning: pip uninstall plus removal of the state and tracing databases, with a note on confirming secure deletion outside Juju's normal flow. Extended sections: - Cryptography D/E: name the actual crypto-providing packages (Python stdlib ssl via urllib.request) and add an explicit at-rest statement. - Security lifecycle: supported-version matrix mirroring SECURITY.md, PyPI update delivery, version-verification commands, and EOL stance.
- Align security lifecycle with SECURITY.md and the tool versions page by mentioning LTS support windows and linking to the versions matrix. - Update logging section to reflect that OWASP-vocabulary security events are already emitted, rather than promised. - Drop internal SSDLC audit references. - Rewrite secure decommissioning to reflect that ops is a library without its own lifecycle.
|
|
||
| ## Product architecture | ||
|
|
||
| Ops sits between Juju and your charm code, and its trust boundaries follow from that position. Juju is the trusted control plane: it dispatches hooks, sets the environment variables and hook command results that Ops reads, and owns the machine or Kubernetes container that the charm runs in. Ops is a library running inside the charm process under Juju's control; it parses the data that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm. Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, to the workload, or to the charm author. The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section. |
There was a problem hiding this comment.
The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section.
Should we link to those sections? Or just drop this sentence?
There was a problem hiding this comment.
I think it would be fine without this sentence.
|
|
||
| ## Secure by Design | ||
|
|
||
| Ops is designed to keep its security surface small. It adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver (see the Cryptographic technology section). It delegates cryptography to Juju and to the Python standard library rather than implementing its own, and it delegates secret storage to Juju secrets. Its persistence is deliberately bounded — a single local state database, plus a local trace buffer when the `tracing` extra is installed — rather than a general-purpose store. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code; the Risks and Good practices sections below set out the practical consequences for charm authors. |
There was a problem hiding this comment.
see the Cryptographic technology section
Should we link here?
the Risks and Good practices sections below
And here?
There was a problem hiding this comment.
I don't think we need to mention the other sections. I have a suggestion that proposes a rewrite to avoid them.
|
|
||
| There is no use of hashing or digital signatures. | ||
|
|
||
| The cryptographic functionality is provided entirely by the Python standard library. The tracing support (the `ops[tracing]` extra, packaged as `ops-tracing`) sends trace data using the standard library `ssl` module via `urllib.request`, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Ops bundles no separate cryptographic library, and the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide the tracing framework rather than the cryptography. |
There was a problem hiding this comment.
| The cryptographic functionality is provided entirely by the Python standard library. The tracing support (the `ops[tracing]` extra, packaged as `ops-tracing`) sends trace data using the standard library `ssl` module via `urllib.request`, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Ops bundles no separate cryptographic library, and the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide the tracing framework rather than the cryptography. | |
| The cryptographic functionality is provided entirely by the Python standard library. The tracing support (the `ops[tracing]` extra, packaged as `ops-tracing`) sends trace data using the standard library `ssl` module via `urllib.request`, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Neither Ops nor the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide any other cryptography implementation. |
There was a problem hiding this comment.
This is quite dense. How about some adjustments for easier readability (building on James's suggestion):
| The cryptographic functionality is provided entirely by the Python standard library. The tracing support (the `ops[tracing]` extra, packaged as `ops-tracing`) sends trace data using the standard library `ssl` module via `urllib.request`, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Ops bundles no separate cryptographic library, and the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide the tracing framework rather than the cryptography. | |
| The cryptographic functionality is provided entirely by the Python standard library. The `ops[tracing]` extra sends data using `urllib.request`, which relies on `ssl` from the standard library, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Neither Ops nor the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide any other cryptography implementation. |
|
|
||
| The cryptographic functionality is provided entirely by the Python standard library. The tracing support (the `ops[tracing]` extra, packaged as `ops-tracing`) sends trace data using the standard library `ssl` module via `urllib.request`, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Ops bundles no separate cryptographic library, and the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide the tracing framework rather than the cryptography. | ||
|
|
||
| Ops does not encrypt the state database or buffered trace data at rest. Confidentiality at rest relies on the filesystem permissions documented in the Charm unit databases section and on the host's at-rest encryption story. |
There was a problem hiding this comment.
in the Charm unit databases section
Link?
There was a problem hiding this comment.
I don't think we need the mention.
| Ops does not encrypt the state database or buffered trace data at rest. Confidentiality at rest relies on the filesystem permissions documented in the Charm unit databases section and on the host's at-rest encryption story. | |
| Ops does not encrypt the state database or buffered trace data at rest. Confidentiality at rest relies on filesystem permissions and the host's at-rest encryption story. |
|
|
||
| ## Logging and monitoring | ||
|
|
||
| Charms log through the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). |
There was a problem hiding this comment.
| Charms log through the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). | |
| Charms use the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). |
As a good practice, never write sensitive data to logs (see the Good practices section).
Link? Or remove this sentence or reword? e.g. "Never write sensitive data to logs."
There was a problem hiding this comment.
I think it's fine to remove. Some additional suggestions for readability:
| Charms log through the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). | |
| Charms use the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju. For example, through `juju debug-log`, using Juju's own log levels and storage. | |
| Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs. |
|
|
||
| ### Security lifecycle | ||
|
|
||
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there; charms pick them up by re-locking and rebuilding, as described above. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year, and a major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. |
There was a problem hiding this comment.
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there; charms pick them up by re-locking and rebuilding, as described above. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year, and a major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. | |
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there. Charms receive updates by re-locking and rebuilding. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year. A major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. |
There was a problem hiding this comment.
Suggest breaking into paragraphs (or refactor to be more like Jubilant):
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there; charms pick them up by re-locking and rebuilding, as described above. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year, and a major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. | |
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there. Charms receive updates by re-locking and rebuilding. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year. A major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). | |
| See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. |
|
|
||
| ## Product architecture | ||
|
|
||
| Ops sits between Juju and your charm code, and its trust boundaries follow from that position. Juju is the trusted control plane: it dispatches hooks, sets the environment variables and hook command results that Ops reads, and owns the machine or Kubernetes container that the charm runs in. Ops is a library running inside the charm process under Juju's control; it parses the data that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm. Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, to the workload, or to the charm author. The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section. |
There was a problem hiding this comment.
From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm.
I have difficulty understanding how the description of what Ops delegates to the charm follows from "your charm code is the least-trusted layer". I'd suggest either expanding on why it's important that Ops treats charm code as less trusted (and how), or dropping that phrase if it's not so important.
|
|
||
| ## Secure by Design | ||
|
|
||
| Ops is designed to keep its security surface small. It adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver (see the Cryptographic technology section). It delegates cryptography to Juju and to the Python standard library rather than implementing its own, and it delegates secret storage to Juju secrets. Its persistence is deliberately bounded — a single local state database, plus a local trace buffer when the `tracing` extra is installed — rather than a general-purpose store. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code; the Risks and Good practices sections below set out the practical consequences for charm authors. |
There was a problem hiding this comment.
| Ops is designed to keep its security surface small. It adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver (see the Cryptographic technology section). It delegates cryptography to Juju and to the Python standard library rather than implementing its own, and it delegates secret storage to Juju secrets. Its persistence is deliberately bounded — a single local state database, plus a local trace buffer when the `tracing` extra is installed — rather than a general-purpose store. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code; the Risks and Good practices sections below set out the practical consequences for charm authors. | |
| Ops is designed to keep its security surface small. It adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver (see the Cryptographic technology section). It delegates cryptography to Juju and to the Python standard library rather than implementing its own, and it delegates secret storage to Juju secrets. Ops only persists a single local state database, plus a local trace buffer when the `tracing` extra is installed. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code; the Risks and Good practices sections below set out the practical consequences for charm authors. |
There was a problem hiding this comment.
How about this refactor, building on James's suggestion. I think the text would flow better into the next section this way.
| Ops is designed to keep its security surface small. It adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver (see the Cryptographic technology section). It delegates cryptography to Juju and to the Python standard library rather than implementing its own, and it delegates secret storage to Juju secrets. Its persistence is deliberately bounded — a single local state database, plus a local trace buffer when the `tracing` extra is installed — rather than a general-purpose store. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code; the Risks and Good practices sections below set out the practical consequences for charm authors. | |
| Ops is designed to keep its security surface small. | |
| Ops only persists a single local state database, plus a local trace buffer when the `tracing` extra is installed. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code. | |
| Ops adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver. It delegates cryptography to Juju and to the Python standard library rather than implementing its own. |
|
|
||
| Ops sits between Juju and your charm code, and its trust boundaries follow from that position. Juju is the trusted control plane: it dispatches hooks, sets the environment variables and hook command results that Ops reads, and owns the machine or Kubernetes container that the charm runs in. Ops is a library running inside the charm process under Juju's control; it parses the data that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm. Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, to the workload, or to the charm author. The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section. | ||
|
|
||
| ## Secure by Design |
There was a problem hiding this comment.
| ## Secure by Design | |
| ## Secure by design |
|
|
||
| Charms log through the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). | ||
|
|
||
| ## Secure decommissioning |
There was a problem hiding this comment.
| ## Secure decommissioning | |
| ## Decommissioning |
|
|
||
| ## Product architecture | ||
|
|
||
| Ops sits between Juju and your charm code, and its trust boundaries follow from that position. Juju is the trusted control plane: it dispatches hooks, sets the environment variables and hook command results that Ops reads, and owns the machine or Kubernetes container that the charm runs in. Ops is a library running inside the charm process under Juju's control; it parses the data that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm. Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, to the workload, or to the charm author. The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section. |
There was a problem hiding this comment.
I think it would be fine without this sentence.
|
|
||
| ## Product architecture | ||
|
|
||
| Ops sits between Juju and your charm code, and its trust boundaries follow from that position. Juju is the trusted control plane: it dispatches hooks, sets the environment variables and hook command results that Ops reads, and owns the machine or Kubernetes container that the charm runs in. Ops is a library running inside the charm process under Juju's control; it parses the data that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm. Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, to the workload, or to the charm author. The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section. |
There was a problem hiding this comment.
I find this quite dense. How about some adjustments, incorporating suggestions from James:
| Ops sits between Juju and your charm code, and its trust boundaries follow from that position. Juju is the trusted control plane: it dispatches hooks, sets the environment variables and hook command results that Ops reads, and owns the machine or Kubernetes container that the charm runs in. Ops is a library running inside the charm process under Juju's control; it parses the data that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. From the perspective of Ops, your charm code is the least-trusted layer: Ops hands it the event context that Juju supplied and otherwise delegates application logic, secret handling, and workload configuration to the charm. Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, to the workload, or to the charm author. The Juju-to-Ops boundary is described in the Inter-process communication section, and the state that Ops keeps on the charm side of that boundary is described in the Charm unit databases section. | |
| Ops sits between Juju and your charm code. Its trust boundaries follow from that position. Juju is the trusted control plane: it provides the hook context that Ops reads, and owns the machine or Kubernetes container where the charm runs. | |
| Ops is a library running inside the charm process under Juju's control. It parses the context that Juju provides, dispatches events to the charm, and persists a small amount of state on the local filesystem. The charm is responsible for application logic, secret handling, and workload configuration. | |
| Ops itself opens no network listeners, manages no credentials, and terminates no TLS — those concerns belong to Juju, the workload, or the charm author. |
|
|
||
| ## Secure by Design | ||
|
|
||
| Ops is designed to keep its security surface small. It adds no daemons or network listeners of its own; the only outbound connection it can make is sending buffered trace data over HTTPS when a charm is integrated with a tracing receiver (see the Cryptographic technology section). It delegates cryptography to Juju and to the Python standard library rather than implementing its own, and it delegates secret storage to Juju secrets. Its persistence is deliberately bounded — a single local state database, plus a local trace buffer when the `tracing` extra is installed — rather than a general-purpose store. As a result, most of a charm's security posture is determined by Juju, by the workload, and by the charm's own code; the Risks and Good practices sections below set out the practical consequences for charm authors. |
There was a problem hiding this comment.
I don't think we need to mention the other sections. I have a suggestion that proposes a rewrite to avoid them.
|
|
||
| The cryptographic functionality is provided entirely by the Python standard library. The tracing support (the `ops[tracing]` extra, packaged as `ops-tracing`) sends trace data using the standard library `ssl` module via `urllib.request`, so the TLS implementation and its cipher suites come from the OpenSSL (or equivalent) library that the running Python interpreter was built against. Ops bundles no separate cryptographic library, and the OpenTelemetry packages that the tracing extra depends on (`opentelemetry-api` and `opentelemetry-sdk`) provide the tracing framework rather than the cryptography. | ||
|
|
||
| Ops does not encrypt the state database or buffered trace data at rest. Confidentiality at rest relies on the filesystem permissions documented in the Charm unit databases section and on the host's at-rest encryption story. |
There was a problem hiding this comment.
I don't think we need the mention.
| Ops does not encrypt the state database or buffered trace data at rest. Confidentiality at rest relies on the filesystem permissions documented in the Charm unit databases section and on the host's at-rest encryption story. | |
| Ops does not encrypt the state database or buffered trace data at rest. Confidentiality at rest relies on filesystem permissions and the host's at-rest encryption story. |
|
|
||
| ## Logging and monitoring | ||
|
|
||
| Charms log through the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). |
There was a problem hiding this comment.
I think it's fine to remove. Some additional suggestions for readability:
| Charms log through the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju (for example, through `juju debug-log`) using Juju's own log levels and storage. Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs (see the Good practices section). | |
| Charms use the Python standard library `logging` module. Ops installs a handler that forwards log records to Juju by running the `juju-log` hook command, so charm and framework log messages are collected and surfaced by Juju. For example, through `juju debug-log`, using Juju's own log levels and storage. | |
| Ops also emits structured security events that follow the [OWASP security-logging vocabulary](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Vocabulary_Cheat_Sheet.html), forwarded to Juju through the same `juju-log` channel. These cover framework-level events such as uncaught exceptions in charm code and hook command authorisation failures. As a good practice, never write sensitive data to logs. |
|
|
||
| For information about supported versions and how to report security issues, see [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md). | ||
|
|
||
| ### Security lifecycle |
There was a problem hiding this comment.
Top-level section would be fine I think
| ### Security lifecycle | |
| ## Security lifecycle |
|
|
||
| If a unit is taken out of service by some means other than `juju remove-unit` (for example, reclaiming the underlying machine or container directly), treat the charm directory the same as any other location that may hold sensitive data, because `StoredState` and buffered deferred-event payloads can contain workload data passed in through events. | ||
|
|
||
| ## Security updates |
There was a problem hiding this comment.
In Jubilant we have a combined Security lifecycle section, which I prefer the structure of. But I'm OK if you want to keep separate sections for updates and lifecycle here.
Another nice thing about the Jubilant one is that it explicitly says that Jubilant uses semantic versioning.
|
|
||
| ### Security lifecycle | ||
|
|
||
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there; charms pick them up by re-locking and rebuilding, as described above. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year, and a major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. |
There was a problem hiding this comment.
Suggest breaking into paragraphs (or refactor to be more like Jubilant):
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there; charms pick them up by re-locking and rebuilding, as described above. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year, and a major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. | |
| Ops is distributed as the `ops` package on [PyPI](https://pypi.org/project/ops/), and security updates are delivered as new releases there. Charms receive updates by re-locking and rebuilding. In line with [SECURITY.md](https://github.com/canonical/operator/blob/main/SECURITY.md), security updates are released for all major versions that have had a release in the last year. A major version that has had no release for over a year is considered end of life. Long Term Support (LTS) releases receive 5 years of support and up to 10 additional years of [extended support](https://ubuntu.com/security/esm). | |
| See the [tool versions page](#tool-versions) for current release dates and end-of-life dates for each supported version. To check which version is installed, run `pip show ops` or `python -c 'import ops; print(ops.__version__)'`. |
This PR extends docs/explanation/security.md to close the SEC0030 V1.3 gaps. This is an extension only; existing sections are unchanged except for the noted Cryptography and Security-lifecycle additions.
Added sections:
Extended sections: