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

Require SQL connection string in strictmode #3517

Merged
merged 3 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ Several of the server options above allow the node to be configured in a way tha
The node can be configured to run in strict mode (default) to prevent any insecure configurations.
Below is a summary of the impact ``strictmode=true`` has on the node and its configuration.

Save storage of any private key material requires some serious consideration.
For this reason the ``crypto.storage`` backend must explicitly be set.
Save storage of any private key material and data requires some serious consideration.
For this reason the ``crypto.storage`` backend and the ``storage.sql.connection`` connection string must explicitly be set.

Private transactions can only be exchanged over authenticated nodes.
Therefore is requires TLS to be configured through ``tls.{certfile,certkeyfile,truststore}``.
Expand Down
3 changes: 1 addition & 2 deletions crypto/cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,10 @@ func Test_fs2VaultCommand(t *testing.T) {
// Configure target
t.Setenv("NUTS_CRYPTO_STORAGE", "vaultkv")
t.Setenv("NUTS_CRYPTO_VAULT_ADDRESS", s.URL)
t.Setenv("NUTS_STRICTMODE", "false")

testDirectory := testIo.TestDirectory(t)
setupFSStoreData(t, testDirectory)
// default datadir is unavailable causing sqlite to fail
t.Setenv("NUTS_DATADIR", testDirectory)

outBuf := new(bytes.Buffer)
cryptoCmd := ServerCmd()
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/deployment/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ Several of the server options above allow the node to be configured in a way tha
The node can be configured to run in strict mode (default) to prevent any insecure configurations.
Below is a summary of the impact ``strictmode=true`` has on the node and its configuration.

Save storage of any private key material requires some serious consideration.
For this reason the ``crypto.storage`` backend must explicitly be set.
Save storage of any private key material and data requires some serious consideration.
For this reason the ``crypto.storage`` backend and the ``storage.sql.connection`` connection string must explicitly be set.

Private transactions can only be exchanged over authenticated nodes.
Therefore is requires TLS to be configured through ``tls.{certfile,certkeyfile,truststore}``.
Expand Down
11 changes: 8 additions & 3 deletions docs/pages/deployment/storage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ Also remember to test your backup and restore procedure.
SQL database
************

By default, storage SQLite will be used in a file called ``sqlite.db`` in the configured data directory.
This can be overridden by configuring a connection string in ``storage.sql.connection``.
Other supported SQL databases are Postgres, MySQL, Microsoft SQL Server and Microsoft Azure SQL Server.
Currently supported SQL databases are Postgres, MySQL, Microsoft SQL Server, Microsoft Azure SQL Server, and SQLite.
The database of your preference can be set by configuring a connection string in ``storage.sql.connection``.
Only in non-strictmode, if no connection string is set this will default to SQLite in a file called ``sqlite.db`` in the configured data directory.

Connection strings must be in the following format:

Expand All @@ -39,6 +39,11 @@ Refer to the documentation of the driver for the database you are using for the
- Azure SQL Server: `github.com/microsoft/go-mssqldb <https://github.com/microsoft/go-mssqldb>`_ (e.g. ``azuresql://server=awesome-server;port=1433;database=awesome-db;fedauth=ActiveDirectoryDefault;``)
- SQLite (e.g. ``sqlite:file:/some/path/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)``)

.. warning::

Usage of SQLite is not recommended for production environments.
Connections to a SQLite DB are restricted to 1, which will lead to severe performance reduction.

Private Keys
************

Expand Down
3 changes: 3 additions & 0 deletions e2e-tests/nuts-network/direct-wan/node-A/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/nuts-network/direct-wan/node-B/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 500
storage:
sql:
connection: "sqlite:file:/opt/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 450
storage:
sql:
connection: "sqlite:file:/opt/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 250
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 250
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 250
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 250
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/nuts-network/ssl-pass-through/node-A/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/nuts-network/ssl-pass-through/node-B/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/openid4vci/issuer-initiated/node-A/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 500
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/openid4vci/issuer-initiated/node-B/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 450
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/openid4vci/network-issuance/node-A/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 500
storage:
sql:
connection: "sqlite:file:/opt/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/openid4vci/network-issuance/node-B/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ network:
grpcaddr: :5555
v2:
gossipinterval: 450
storage:
sql:
connection: "sqlite:file:/opt/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
4 changes: 0 additions & 4 deletions e2e-tests/ops/create-subject/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,5 @@ services:
image: "${IMAGE_NODE_A:-nutsfoundation/nuts-node:master}"
ports:
- "18081:8081"
environment:
NUTS_CONFIGFILE: /opt/nuts/nuts.yaml
volumes:
- "./nuts.yaml:/opt/nuts/nuts.yaml:ro"
healthcheck:
interval: 1s # Make test run quicker by checking health status more often
3 changes: 3 additions & 0 deletions e2e-tests/ops/key-rotation/node-A/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/ops/key-rotation/node-B/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
2 changes: 2 additions & 0 deletions e2e-tests/storage/redis/node-A/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ storage:
redis:
address: redis:6379
database: nodeA
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
2 changes: 2 additions & 0 deletions e2e-tests/storage/redis/node-B/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ storage:
redis:
address: redis:6379
database: nodeB
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
3 changes: 3 additions & 0 deletions e2e-tests/storage/vault/nuts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ tls:
truststorefile: /opt/nuts/truststore.pem
certfile: /opt/nuts/certificate-and-key.pem
certkeyfile: /opt/nuts/certificate-and-key.pem
storage:
sql:
connection: "sqlite:file:/nuts/data/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)"
12 changes: 12 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/nuts-foundation/nuts-node/events"
httpEngine "github.com/nuts-foundation/nuts-node/http"
"github.com/nuts-foundation/nuts-node/network"
"github.com/nuts-foundation/nuts-node/storage"
"github.com/nuts-foundation/nuts-node/test"
"github.com/nuts-foundation/nuts-node/test/pki"
v1 "github.com/nuts-foundation/nuts-node/vdr/api/v1"
Expand Down Expand Up @@ -146,6 +147,17 @@ func startServer(testDirectory string, exitCallback func(), serverConfig core.Se
if err != nil {
panic(err)
}
if serverConfig.Strictmode {
type modCfg struct {
Storage storage.Config `koanf:"storage"`
}
storageConfig := modCfg{Storage: storage.DefaultConfig()}
storageConfig.Storage.SQL.ConnectionString = fmt.Sprintf("sqlite:file:%s/sqlite.db?_pragma=foreign_keys(1)&journal_mode(WAL)", testDirectory)
err = koanfInstance.Load(structs.ProviderWithDelim(storageConfig, "koanf", "."), nil)
if err != nil {
panic(err)
}
}

bytes, err := koanfInstance.Marshal(yamlParser)
if err != nil {
Expand Down
8 changes: 6 additions & 2 deletions storage/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ func (e *engine) Configure(config core.ServerConfig) error {
e.databases = append(e.databases, bboltDB)

// SQL storage
if err := e.initSQLDatabase(); err != nil {
if err := e.initSQLDatabase(config.Strictmode); err != nil {
return fmt.Errorf("failed to initialize SQL database: %w", err)
}

Expand Down Expand Up @@ -212,9 +212,13 @@ func (e *engine) GetSQLDatabase() *gorm.DB {

// initSQLDatabase initializes the SQL database connection.
// If the connection string is not configured, it defaults to a SQLite database, stored in the node's data directory.
func (e *engine) initSQLDatabase() error {
func (e *engine) initSQLDatabase(strictmode bool) error {
connectionString := e.config.SQL.ConnectionString
if len(connectionString) == 0 {
if strictmode {
return errors.New("no database configured: storage.sql.connection must be set in strictmode")
}
// non-strictmode uses SQLite as default
connectionString = sqliteConnectionString(e.datadir)
}

Expand Down
8 changes: 7 additions & 1 deletion storage/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,15 @@ func Test_engine_sqlDatabase(t *testing.T) {
require.NoError(t, os.Remove(dataDir))
e := New()
e.(*engine).datadir = dataDir
err := e.(*engine).initSQLDatabase()
err := e.(*engine).initSQLDatabase(false)
assert.ErrorContains(t, err, "unable to open database file")
})
t.Run("no DB configured in strictmode", func(t *testing.T) {
e := New()
e.(*engine).datadir = io.TestDirectory(t)
err := e.(*engine).initSQLDatabase(true)
assert.ErrorContains(t, err, "no database configured: storage.sql.connection must be set in strictmode")
})
t.Run("sqlite is restricted to 1 connection", func(t *testing.T) {
e := New()
require.NoError(t, e.Configure(core.ServerConfig{Datadir: t.TempDir()}))
Expand Down
Loading