Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HSM 1: KMIP walking skeleton (#566) #679

Merged

Conversation

ximon18
Copy link
Member

@ximon18 ximon18 commented Sep 28, 2021

Introduces a KMIP signer, disabled by default.

The scope for this PR is deliberately limited. The KMIP signer itself is fully functional but it is not yet fully wired into Krill. It is not configurable, it has no metrics, it has no persistent mapping of Krill key identifiers to HSM key identifiers (update: added in PR #686 for that), it doesn't support async operation (update: async will not be added at the moment), there's no extensions to the API or CLI to see which Signer owns a particular key, etc. This PR is just about showing that the Krill test suite passes when forcing Krill to use a PyKMIP server via the new KMIP signer.

KMIP support can only be enabled currently by using BOTH the hsm and hsm-tests feature flags. In normal usage we may want to use a local signer for some operations even when using a KMIP signer for others. The hsm-tests feature flag forces Krill to use KMIP for ALL operations. This is used by a new GitHub Actions hsmtest job in the CI workflow to test Krill against PyKMIP. If you look at the test log output you can see lines like the following:

2021-10-05 11:32:09 [DEBUG] [krill::commons::crypto::signers::kmip::internal] Probing server at 127.0.0.1:5696
2021-10-05 11:32:09 [WARN] [krill::commons::crypto::signers::kmip::internal] KMIP server lacks support for one or more required operations: ModifyAttribute
2021-10-05 11:32:09 [INFO] [krill::commons::crypto::signers::kmip::internal] Using KMIP server 'PyKMIP 0.10.0 Software Server' at 127.0.0.1:5696

To be discussed.

  • OpenSSL is used as it was difficult to make RustLS connect to PyKMIP, and while eventually that was solved it may be unhelpful to customers to force the strict "no unsafe features (e.g. self-signed certificates) and no obsolete crpytography" opinions of RustLS on them as it may be too strict for real world HSM deployments.

Other notes:

  • Uses newly released bcder crate DER unsigned integer support.
  • Lacks tests of its own though is tested by the Krill test suite and the kmip-protocol and kmip-ttlv crates have tests, not exhaustive but also quite a bit more than nothing.
  • The target server is hard-coded to local host with certificates for testing with PyKMIP. In fact there are no changes anywhere in Krill other than adding support for this signer as a replacement for the existing OpenSSL based "soft signer".

Details:

  • Adds a dependency on the kmip-protocol crate for TCP+TLS high level KMIP client support based on the underlying kmip-ttlv crate, neither of which has been reviewed yet.
  • Adds a dependency on the backoff crate for retry support.
  • Adds a dependency on the r2d2 crate for connection pooling support.
  • Refactor signers to crypto::signers and replace the Dummy signer with a KMIP signer.
  • Added a "hsmtest" job to the GitHub Actions CI workflow that runs all Krill tests using the KMIP signer against PyKMIP.
  • Added a "hsm-tests" Cargo feature flag for configuring Krill to use ONLY KMIP as a signer, not OpenSSL at all.
    Currently building without the "hsm-tests" feature flag set will fail if the "hsm" feature flag is set.
    Krill isn't ready to be used in "hsm" mode yet.
  • Introduces SignerRouter between KrillSigner and SignerProvider, to implement the Signer trait so that it can be passed to builders so that their invocation of a signer also goes via SignerRouter thus dispatching to the correct signer.

This PR doesn't offer any way to see that the keys have actually been created. However, the tests pass, keys are created and signing is done, the KMIP signer is shown connecting to the PyKMIP server in the logs, and the OpenSSL signer is disabled by the feature flags used by the hsmtest job. If you watch the PyKMIP log while the test is running you can see that it is connecting and executing KMIP operations.

Update: I've updated the GH Actions CI workflow in this PR branch to always dump the PyKMIP log file, not only on error, which should make it easier for reviewers to see that there is indeed some activity.

Using a custom local KMIP client when I inspected the keys inside my local PyKMIP instance before and after running the Krill test suite, before it was empty, and after it looked like something this:

Key: 1787, Name: 'krill-public-key-2a5d9ec24d8b8fe7a17b24d15a381c01c0b47c7b'
Key: 1788, Name: 'krill-private-key-2a5d9ec24d8b8fe7a17b24d15a381c01c0b47c7b'
Key: 1765, Name: 'krill-public-key-d46af8f74d79055a0d0da6ff806f089c8f18eb30'
Key: 1766, Name: 'krill-private-key-d46af8f74d79055a0d0da6ff806f089c8f18eb30'
Key: 1755, Name: 'krill-public-key-cd27dfee6834107489e2eebb54899b8c9038d1a8'
Key: 1756, Name: 'krill-private-key-cd27dfee6834107489e2eebb54899b8c9038d1a8'
...
Key: 3, Name: 'krill-public-key-a3897008c85f8ad7ad2658c89e1dcdbca6301485'
Key: 4, Name: 'krill-private-key-a3897008c85f8ad7ad2658c89e1dcdbca6301485'
Key: 5, Name: 'krill-public-key-7809b44da1d6be664db7cabd7deb9009c94ff5c3'
Key: 6, Name: 'krill-private-key-7809b44da1d6be664db7cabd7deb9009c94ff5c3'
Key: 1, Name: 'krill-public-key-0daebf72d4b7aecf00da86db43ed220a3df78c59'
Key: 2, Name: 'krill-private-key-0daebf72d4b7aecf00da86db43ed220a3df78c59'

If you run Krill with trace level logging enabled you will then see a stripped diagnostic representation of the KMIP requests and responses being sent and received, e.g.:

2021-10-05 17:10:47 [TRACE] [kmip_protocol::client::client] KMIP TTLV request: 78[77[69[6Ai6Bi]0Di]0F[5Ce2:79[1F[08[0At0Be4:]08[0At0Bi]]65[08[0At0B[55t54e1:]]08[0At0Bi]]6E[08[0At0B[55t54e1:]]08[0At0Bi]]]]]
2021-10-05 17:10:47 [TRACE] [kmip_protocol::client::client] KMIP TTLV response: 7B[7A[69[6Ai6Bi]92d0Di]0F[5Ce2:7Fe0:7C[66t6Ft]]]

The diag_to_txt example included with the kmip-protocol crate can render these diagnostic strings in slightly more readable form, e.g. the first line from the log example above renders like so:

 cargo run --example diag_to_txt /tmp/r
   Compiling kmip-protocol v0.3.3-dev (/home/ximon/src/krill-kmip-protocol)
    Finished dev [unoptimized + debuginfo] target(s) in 4.37s
     Running `target/debug/examples/diag_to_txt /tmp/r`
Tag: Request Message (0x420078), Type: Structure (0x01), Data: 
  Tag: Request Header (0x420077), Type: Structure (0x01), Data: 
    Tag: Protocol Version (0x420069), Type: Structure (0x01), Data: 
      Tag: Protocol Version Major (0x42006A), Type: Integer (0x02), Data: <redacted>
      Tag: Protocol Version Minor (0x42006B), Type: Integer (0x02), Data: <redacted>
    Tag: Batch Count (0x42000D), Type: Integer (0x02), Data: <redacted>
  Tag: Batch Item (0x42000F), Type: Structure (0x01), Data: 
    Tag: Operation (0x42005C), Type: Enumeration (0x05), Data: 2
    Tag: Request Payload (0x420079), Type: Structure (0x01), Data: 
      Tag: Common Template-Attribute (0x42001F), Type: Structure (0x01), Data: 
        Tag: Attribute (0x420008), Type: Structure (0x01), Data: 
          Tag: Attribute Name (0x42000A), Type: TextString (0x07), Data: <redacted>
          Tag: Attribute Value (0x42000B), Type: Enumeration (0x05), Data: 4
        Tag: Attribute (0x420008), Type: Structure (0x01), Data: 
          Tag: Attribute Name (0x42000A), Type: TextString (0x07), Data: <redacted>
          Tag: Attribute Value (0x42000B), Type: Integer (0x02), Data: <redacted>
      Tag: Private Key Template-Attribute (0x420065), Type: Structure (0x01), Data: 
        Tag: Attribute (0x420008), Type: Structure (0x01), Data: 
          Tag: Attribute Name (0x42000A), Type: TextString (0x07), Data: <redacted>
          Tag: Attribute Value (0x42000B), Type: Structure (0x01), Data: 
            Tag: Name Value (0x420055), Type: TextString (0x07), Data: <redacted>
            Tag: Name Type (0x420054), Type: Enumeration (0x05), Data: 1
        Tag: Attribute (0x420008), Type: Structure (0x01), Data: 
          Tag: Attribute Name (0x42000A), Type: TextString (0x07), Data: <redacted>
          Tag: Attribute Value (0x42000B), Type: Integer (0x02), Data: <redacted>
      Tag: Public Key Template-Attribute (0x42006E), Type: Structure (0x01), Data: 
        Tag: Attribute (0x420008), Type: Structure (0x01), Data: 
          Tag: Attribute Name (0x42000A), Type: TextString (0x07), Data: <redacted>
          Tag: Attribute Value (0x42000B), Type: Structure (0x01), Data: 
            Tag: Name Value (0x420055), Type: TextString (0x07), Data: <redacted>
            Tag: Name Type (0x420054), Type: Enumeration (0x05), Data: 1
        Tag: Attribute (0x420008), Type: Structure (0x01), Data: 
          Tag: Attribute Name (0x42000A), Type: TextString (0x07), Data: <redacted>
          Tag: Attribute Value (0x42000B), Type: Integer (0x02), Data: <redacted>

Operation code 2 is Create Key Pair according to the KMIP specification (see KMIP 1.0 section 9.1.3.2.26 Operation Enumeration).

The second log line, the response, renders like this:

❯ cargo run --example diag_to_txt /tmp/r2
    Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/examples/diag_to_txt /tmp/r2`
Tag: Response Message (0x42007B), Type: Structure (0x01), Data: 
  Tag: Response Header (0x42007A), Type: Structure (0x01), Data: 
    Tag: Protocol Version (0x420069), Type: Structure (0x01), Data: 
      Tag: Protocol Version Major (0x42006A), Type: Integer (0x02), Data: <redacted>
      Tag: Protocol Version Minor (0x42006B), Type: Integer (0x02), Data: <redacted>
    Tag: Time Stamp (0x420092), Type: DateTime (0x09), Data: <redacted>
    Tag: Batch Count (0x42000D), Type: Integer (0x02), Data: <redacted>
  Tag: Batch Item (0x42000F), Type: Structure (0x01), Data: 
    Tag: Operation (0x42005C), Type: Enumeration (0x05), Data: 2
    Tag: Result Status (0x42007F), Type: Enumeration (0x05), Data: 0
    Tag: Response Payload (0x42007C), Type: Structure (0x01), Data: 
      Tag: Private Key Unique Identifier (0x420066), Type: TextString (0x07), Data: <redacted>
      Tag: Public Key Unique Identifier (0x42006F), Type: TextString (0x07), Data: <redacted>

This shows a successful response that includes the internal PyKMIP identifiers for the created keys (which are redacted in the diagnostic output).

@ximon18 ximon18 changed the base branch from main to dev September 28, 2021 14:50
@ximon18 ximon18 changed the title Issue 566 implement krill kmip based signer implementation KMIP walking skeleton (#566) Sep 28, 2021
@ximon18 ximon18 linked an issue Sep 28, 2021 that may be closed by this pull request
- Add a dependency on the backoff crate for retry support.
- Add a dependency on the r2d2 crate for connection pooling support.
- Uses GitHub versions of the bcder and rpki crates for the DER Unsigned Integer support needed by the KMIP signer.
- Refactor signers to crypto::signers and replace the Dummy signer with a KMIP signer.
- Added a "hsmtest" job to the GitHub Actions CI workflow that runs all Krill tests using the KMIP signer against PyKMIP.
- Added a "hsm-tests" Cargo feature flag for configuring Krill to use ONLY KMIP as a signer, not OpenSSL at all.
  Currently building without the "hsm-tests" feature flag set will fail if the "hsm" feature flag is set.
  Krill isn't ready to be used in "hsm" mode yet.
- Changes SignerProvider to implement the Signer trait so that it can be passed to builders so that their invocation of a signer also goes via SignerProvider dispatching to the correct signer.
@ximon18 ximon18 force-pushed the issue-566-implement-krill-kmip-based-signer-implementation branch from 575745d to 870a102 Compare October 5, 2021 11:26
@ximon18 ximon18 requested a review from timbru October 5, 2021 15:00
@ximon18 ximon18 marked this pull request as ready for review October 5, 2021 15:03
…er. Previously some Krill logic when invoked was given the same signer as handling the current purpose to invoke later even if for a different purpose. If the initial purpose required the KMIP signer as the key owning signer but the later purpose was one-off signing then that should be able to be routed if desired to the OpenSslSigner, for example. Introduces another layer of indirection: RouterSigner.
src/commons/crypto/signing.rs Outdated Show resolved Hide resolved
"router", not "dispatcher", and don't lock the entire SignerRouter for create/delete key operations.
@ximon18 ximon18 added the hsm Relates to adding HSM support to Krill label Oct 14, 2021
@ximon18 ximon18 requested a review from partim October 25, 2021 15:29
@ximon18 ximon18 changed the title KMIP walking skeleton (#566) HSM 1: KMIP walking skeleton (#566) Nov 10, 2021
src/commons/crypto/signers/kmip/internal.rs Show resolved Hide resolved
src/commons/crypto/signers/kmip/signer.rs Outdated Show resolved Hide resolved
src/commons/crypto/signing.rs Outdated Show resolved Hide resolved
doc/development/hsm/architecture.md Show resolved Hide resolved
src/commons/crypto/signers/kmip/internal.rs Show resolved Hide resolved
src/commons/crypto/signers/kmip/internal.rs Show resolved Hide resolved
@ximon18
Copy link
Member Author

ximon18 commented Nov 15, 2021

@timbru : Am I right in thinking that your review didn't including looking at the kmip-protocol crate dependency code or the kmip-ttlv crate that it depends on, both of which were written by me and whose code is also in NLnet Labs GitHub repositories?

@timbru
Copy link
Contributor

timbru commented Nov 15, 2021

@timbru : Am I right in thinking that your review didn't including looking at the kmip-protocol crate dependency code or the kmip-ttlv crate that it depends on, both of which were written by me and whose code is also in NLnet Labs GitHub repositories?

Indeed. I am just focussing on krill itself here - I am happy to look at the kmip libs as a separate effort.

@ximon18 ximon18 changed the base branch from dev to hsm November 22, 2021 21:46
@ximon18 ximon18 merged commit 936dbda into hsm Nov 23, 2021
@ximon18 ximon18 deleted the issue-566-implement-krill-kmip-based-signer-implementation branch November 23, 2021 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hsm Relates to adding HSM support to Krill
Projects
None yet
2 participants