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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with restore from backup for operational container #5

Closed
dvzrv opened this issue Feb 8, 2024 · 10 comments
Closed

Issues with restore from backup for operational container #5

dvzrv opened this issue Feb 8, 2024 · 10 comments

Comments

@dvzrv
Copy link

dvzrv commented Feb 8, 2024

Hi! 馃憢

I'm currently working on a higher-level Rust library for the nethsm (based on nethsm-sdk-rs) and the last remaining test-case I am not able to get to work currently is the restore from backup scenario.

I am able to get things to work using plain curl, e.g. with

curl -k -X 'POST' \
  'https://localhost:39221/api/v1/system/restore' \
  -H 'Authorization: Basic YWRtaW46anVzdC1hbi1hZG1pbi1wYXNzcGhyYXNl' \
  -H 'accept: */*' \
  -H 'Content-Type: multipart/form-data' \
  -F 'arguments={
  "backupPassphrase": "just-a-backup-passphrase",
  "systemTime": "2024-02-08T13:40:53.599Z"
}' \
  -F 'backup_file=@nethsm-backup'

With the backup file being (zipped for upload):
nethsm-backup.zip

(The above is using dummy data, with an admin account that has just-an-admin-passphrase as passphrase)

FWIW: When leaving out the Authorization header in the curl call, I am getting the same response code as described in the issue below:

When using nethsm-sdk-rs, it appears as if no credentials are being used (although provided to system_restore_post) when trying to communicate with a provisioned container (in "Operational" state), leading to a 401 response code.

When comparing the function declaration to that of e.g. system_reboot_post it becomes clear that authentication and authorization handling is missing (similar to how it is done here):

https://github.com/Nitrokey/nethsm-sdk-rs/blob/569321d82d8717221b056cb96587ca42d4574e1c/src/apis/default_api.rs#L3313-L3317

I guess system_restore_post may only work for unprovisioned units (container or otherwise) when using nethsm-sdk-rs at this point in time.

Additionally, getting an example curl command call from the OpenAPI interface (https://nethsmdemo.nitrokey.com/api_docs/index.html#/default/post_system_restore), even if previously authorized, the curl call for that endpoint will not contain an Authorization header (others do)!
My assumption is therefore, that the code from which the OpenAPI client code is being generated is likely causing the issue I am seeing in nethsm-sdk-rs.
As the restore endpoint is also supposed to be used for unprovisioned units, where no login credentials are required, it appears as if this code path is being preferred and somehow breaks the use-case where an already operational unit should be restored.

@dvzrv
Copy link
Author

dvzrv commented Feb 8, 2024

After some further investigation I am unfortunately also unable to get restore working for an unprovisioned system using nethsm-sdk-rs.

A curl call similar to this one works (reusing the artifacts that are created in my tests):

curl -k -X 'POST' \
  'https://localhost:34387/api/v1/system/restore' \
  -H 'accept: */*' \
  -H 'Content-Type: multipart/form-data' \
  -F 'arguments={
  "backupPassphrase": "just-a-backup-passphrase",
  "systemTime": "2024-02-08T13:40:53.599Z"
}' \
  -F 'backup_file=@nethsm-backup'

(the container ends up in "Locked" state)

Calling this endpoint through the Rust SDK however does not work and I always get a 400 response code. It is unclear whether this has overlap with Nitrokey/nethsm-sdk-py#93.
I have tried calling the endpoint multiple times in a row (which somehow seems to fix the issue for the Python SDK), but that did not change anything for this problem.

It is a bit unfortunate, but it appears that using the Rust SDK it is currently impossible to do system restore.

@ansiwen
Copy link
Collaborator

ansiwen commented Apr 24, 2024

Thanks for the report! It seems to be an SDK issue, right? Could you file it against https://github.com/Nitrokey/nethsm-sdk-py/issues/ then? I don't think the SDK/client developers are watching here. Thanks!

@dvzrv
Copy link
Author

dvzrv commented May 4, 2024

I have reported this in Nitrokey/nethsm-sdk-rs#15 but would like to keep this issue open for as long as there is no feedback/resolve if that is okay with you.

@robin-nitrokey
Copy link
Member

I don鈥檛 think this is an SDK issue originally. The API spec does not set the security field for the POST /system/restore endpoint, so the client has no way to tell that the endpoint supports basic authentication:

nethsm/docs/nethsm-api.yaml

Lines 1821 to 1846 in 56c16d7

/system/restore:
post:
responses:
"204":
description: Successful restore from backup data.
"400":
description: Bad request - restore did not apply.
"406":
description: Content type in Accept header not supported.
"412":
description: |
Precondition failed (NetHSM was not *Unprovisioned* or
*Operational*).
description: |
Restore the key store and user store from a backup file. If NetHSM is
*Unprovisioned*, then the configuration is restored.
requestBody:
content:
multipart/form-data:
schema:
$ref: "#/components/schemas/RestoreRequest"
x-annotation-role:
- Public
x-annotation-state:
- Unprovisioned
- Operational

Compare for example the GET /keys endpoint:

nethsm/docs/nethsm-api.yaml

Lines 244 to 245 in 56c16d7

security:
- basic: []

I think it should work if the API spec is corrected.

@ansiwen
Copy link
Collaborator

ansiwen commented May 6, 2024

I see. The problem is, that this endpoint has two modes, depending on the state of NetHSM. A full restore in "Unprovisioned" state does not need Basic Authentication. So, would the SDK then still allow that, if we add it to the OpenAPI spec? I guess we have to check the exact semantics in the OpenAPI definitions.

@robin-nitrokey
Copy link
Member

In the Rust SDK, there are two relevant settings: You can globally set the credentials to use. Then the client decides whether to send these credentials depending on the security settings of the endpoint. As far as I see, it is not enforced that they are actually set. So I think it should work fine.

AFAIK the Python SDK only has the global setting and not the per-endpoint checks, though I would have to double-check that.

I don鈥檛 know how that relates to the definitions in the OpenAPI spec.

@ansiwen
Copy link
Collaborator

ansiwen commented May 6, 2024

Aha, it's possible to specify optional authentication: https://stackoverflow.com/a/48196118/3750161
The question of course is, if the code generators can handle it. 馃槒

@robin-nitrokey
Copy link
Member

The optional authentication seems to work both with the Rust and the Python generator:

@ansiwen
Copy link
Collaborator

ansiwen commented May 6, 2024

Thanks a lot for testing. Will fix the OpenAPI spec accordingly.

@ansiwen
Copy link
Collaborator

ansiwen commented May 7, 2024

This should have been fixed in 67f52f2. Since the code generation seems to work, I will close this here. The rest should be handled in Nitrokey/nethsm-sdk-rs#15.

@ansiwen ansiwen closed this as completed May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants