Skip to content

Implement and configure Docker secrets for private key management - #7

Open
dlt-green wants to merge 8 commits into
sdellava:mainfrom
dlt-green:main
Open

Implement and configure Docker secrets for private key management#7
dlt-green wants to merge 8 commits into
sdellava:mainfrom
dlt-green:main

Conversation

@dlt-green

Copy link
Copy Markdown
Contributor

This pull request introduces support for securely loading the node's private key from a Docker Secret file instead of only from environment variables or local files. It updates the Docker Compose configuration and the key loading logic to handle secret files, and enhances the update script to automatically prepare the Docker Secret from the .env file if present. Minor cleanups and improvements are also included.

Secure private key management:

  • node/docker-compose.yml: Configures the node service to use a Docker Secret (node_privatekey) for the private key, removing the previous volume mount for keys. The secret is sourced from privatekey.txt.
  • node/src/keys.ts: Adds logic to load the node's private key from a file specified by the NODE_1_PRIVATEKEY_FILE environment variable (set by Docker Secrets), falling back to the previous environment variable or generating a new key if not found. Includes logging for key loading and generation.

Update script enhancements:

  • update.sh: Adds a prepare_docker_secrets function that extracts NODE_1_PRIVATEKEY from .env and writes it to privatekey.txt for Docker Secrets, with appropriate permissions. This function is called before starting Docker services. [1] [2]
  • update.sh: Minor cleanups, such as removing unnecessary blank lines and ensuring required commands are checked before use. [1] [2] [3] [4]

These changes improve the security and automation of private key handling for the node service in Docker environments.

✅ Complete Final Summary – Secure Private Key Handling with Docker Secrets

Here’s a clear overview of all the changes needed to fully solve the private key security issue.

1. docker-compose.yml (in the node/ folder)

Goal: Pass the private key as a Docker Secret (mounted as a file in RAM) instead of an environment variable.

Key changes:

  • Add NODE_1_PRIVATEKEY_FILE pointing to the secret path
  • Add a secrets: section under the service
  • Define the secret at the bottom of the file
YAML
environment:
  NODE_ID: "1"
  NODE_OPTIONS: --dns-result-order=ipv4first
  NODE_1_PRIVATEKEY_FILE: /run/secrets/node_privatekey     # ← NEW

secrets:
  - node_privatekey

secrets:
  node_privatekey:
    file: ./privatekey.txt

2. update.sh

Changes made:

  • Added a new function prepare_docker_secrets()
  • This function automatically extracts NODE_1_PRIVATEKEY from .env and creates privatekey.txt
  • The function is called right before starting the node container

Benefit: You can keep using .env as your single source of truth. The script converts the key into a secure Docker Secret automatically.

3. src/keys.ts

Main improvement:

The loadOrCreateNodeIdentity() function now follows this priority order:

Priority | Source | Security Level -- | -- | -- 1 | Local file keys/oracle_node_*.iotaprivkey | High 2 | Docker Secret (NODE_1_PRIVATEKEY_FILE) | Very High 3 | Environment variable from .env | Medium 4 | Generate new key | —

Final Workflow After Changes

  1. Run ./update.sh --skip-local-build
  2. update.sh automatically creates privatekey.txt from .env
  3. Docker Compose mounts it as a secret
  4. keys.ts loads the key preferably from the Docker Secret
  5. The private key is no longer visible via docker inspect, env, or logs

Added function to prepare Docker secrets from .env file.
Updated docker-compose.yml to include Docker secrets for private key and removed volume mapping for keys.
Implement Docker secrets preparation for private key
Removed comments about private key handling and healthcheck.
Removed comments and adjusted fallback logic for private key retrieval.
Removed Docker Secrets preparation section and related comments.
@sdellava

Copy link
Copy Markdown
Owner

The PR is a good direction, but in its current form it does not fully remove the private key from the environment.

update.sh creates node/privatekey.txt from NODE_1_PRIVATEKEY in node/.env, then Docker mounts that file as a secret at /run/secrets/node_privatekey.

However, the script does not delete or clear NODE_1_PRIVATEKEY from node/.env.

In addition in the .evn file we have other secrets for LLM and IPFS.

Because node/docker-compose.yml still includes:
env_file:

  • .env

the private key will still be injected into the container environment if it remains in .env.

The application will prefer reading the key from the Docker Secret file, but the same secret may still be present as an environment variable.

So the security improvement is only partial.

It becomes significantly safer only if update.sh also removes NODE_1_PRIVATEKEY from node/.env after writing privatekey.txt, or if the private key is moved out of .env manually before running Docker.

In short: Docker Secrets are a safer mechanism, but this PR does not yet complete the migration away from environment-based private key exposure.

@dlt-green

Copy link
Copy Markdown
Contributor Author

Current State & Limitations
As you correctly noted:

update.sh extracts NODE_1_PRIVATEKEY from node/.env and creates privatekey.txt, which is then mounted as a Docker Secret at /run/secrets/node_privatekey.
However, the original value remains in .env.
Because docker-compose.yml still uses env_file: .env, the key can still be injected into the container as an environment variable.
While the application now prefers reading from the Docker Secret file, the secret may still exist in the environment. This means the security gain is only partial.

We fully agree that this is not the final state.

Our Design Rationale
We deliberately kept NODE_1_PRIVATEKEY in .env as a fallback for the following reasons:

Several other validators are currently running older versions of the deployment scripts and prefer a single, simple configuration file (.env).
A sudden breaking change would have caused operational friction for them.
We wanted to introduce Docker Secrets in a non-breaking way first, so operators can gradually adopt the new mechanism.

At the same time, we share your view that the long-term direction should be:

Use .env only for management, but never mount it 1:1 into production containers. Instead, extract sensitive values and inject them via Docker Secrets (or a proper secrets manager).

This principle should ideally apply not only to the private key, but also to other secrets such as LLM_API_KEY and IPFS_BEARER_TOKEN.

Introduce the split into config.env + secrets.env + individual secret files.

Proposed Next Steps
We are planning the following improvements:

Automatic cleanup in update.sh
After successfully creating privatekey.txt, optionally remove or comment out NODE_1_PRIVATEKEY from .env (with a clear comment and backup).
Broader secret extraction
Extend the mechanism to handle other sensitive values (LLM_API_KEY, IPFS_BEARER_TOKEN, etc.) via Docker Secrets instead of relying solely on env_file.
Clear migration path & documentation
Provide operators with a clear migration guide and a configuration flag (e.g. USE_DOCKER_SECRETS=true) so they can opt into the stricter mode.

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

Successfully merging this pull request may close these issues.

2 participants