Skip to content

Commit

Permalink
MF-448 - Option for Postgres SSL Mode (#449)
Browse files Browse the repository at this point in the history
* MF-448 - Option for Postgres SSL Mode

Adds an option to choose the ssl mode when connecting to postgres.
Only supporting disable or require for now with verify-ca and verify-full to come after more discussion.

Signed-off-by: Michael Finley <Michael.Finley@target.com>

* Changing package name back

Accidentally changed the package name so reverting that!

Signed-off-by: Michael Finley <Michael.Finley@target.com>

* Adding section in getting-started for securing pgsql connections

Signed-off-by: Michael Finley <Michael.Finley@target.com>
  • Loading branch information
mfinley3 authored and anovakovic01 committed Nov 7, 2018
1 parent ec0a148 commit eb38c36
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 42 deletions.
6 changes: 5 additions & 1 deletion cmd/things/main.go
Expand Up @@ -43,6 +43,7 @@ const (
defDBUser = "mainflux"
defDBPass = "mainflux"
defDBName = "things"
defDBSSLMode = "disable"
defCACerts = ""
defCacheURL = "localhost:6379"
defCachePass = ""
Expand All @@ -58,6 +59,7 @@ const (
envDBUser = "MF_THINGS_DB_USER"
envDBPass = "MF_THINGS_DB_PASS"
envDBName = "MF_THINGS_DB"
envDBSSLMode = "MF_THINGS_DB_SSL_MODE"
envCACerts = "MF_THINGS_CA_CERTS"
envCacheURL = "MF_THINGS_CACHE_URL"
envCachePass = "MF_THINGS_CACHE_PASS"
Expand All @@ -76,6 +78,7 @@ type config struct {
DBUser string
DBPass string
DBName string
DBSSLMode string
CACerts string
CacheURL string
CachePass string
Expand Down Expand Up @@ -126,6 +129,7 @@ func loadConfig() config {
DBUser: mainflux.Env(envDBUser, defDBUser),
DBPass: mainflux.Env(envDBPass, defDBPass),
DBName: mainflux.Env(envDBName, defDBName),
DBSSLMode: mainflux.Env(envDBSSLMode, defDBSSLMode),
CACerts: mainflux.Env(envCACerts, defCACerts),
CacheURL: mainflux.Env(envCacheURL, defCacheURL),
CachePass: mainflux.Env(envCachePass, defCachePass),
Expand Down Expand Up @@ -154,7 +158,7 @@ func connectToCache(cacheURL, cachePass string, cacheDB string, logger logger.Lo
}

func connectToDB(cfg config, logger logger.Logger) *sql.DB {
db, err := postgres.Connect(cfg.DBHost, cfg.DBPort, cfg.DBName, cfg.DBUser, cfg.DBPass)
db, err := postgres.Connect(cfg.DBHost, cfg.DBPort, cfg.DBName, cfg.DBUser, cfg.DBPass, cfg.DBSSLMode)
if err != nil {
logger.Error(fmt.Sprintf("Failed to connect to postgres: %s", err))
os.Exit(1)
Expand Down
6 changes: 5 additions & 1 deletion cmd/users/main.go
Expand Up @@ -40,6 +40,7 @@ const (
defDBUser = "mainflux"
defDBPass = "mainflux"
defDBName = "users"
defDBSSLMode = "disable"
defHTTPPort = "8180"
defGRPCPort = "8181"
defSecret = "users"
Expand All @@ -51,6 +52,7 @@ const (
envDBUser = "MF_USERS_DB_USER"
envDBPass = "MF_USERS_DB_PASS"
envDBName = "MF_USERS_DB"
envDBSSLMode = "MF_USERS_DB_SSL_MODE"
envHTTPPort = "MF_USERS_HTTP_PORT"
envGRPCPort = "MF_USERS_GRPC_PORT"
envSecret = "MF_USERS_SECRET"
Expand All @@ -65,6 +67,7 @@ type config struct {
DBUser string
DBPass string
DBName string
DBSSLMode string
HTTPPort string
GRPCPort string
Secret string
Expand Down Expand Up @@ -106,6 +109,7 @@ func loadConfig() config {
DBUser: mainflux.Env(envDBUser, defDBUser),
DBPass: mainflux.Env(envDBPass, defDBPass),
DBName: mainflux.Env(envDBName, defDBName),
DBSSLMode: mainflux.Env(envDBSSLMode, defDBSSLMode),
HTTPPort: mainflux.Env(envHTTPPort, defHTTPPort),
GRPCPort: mainflux.Env(envGRPCPort, defGRPCPort),
Secret: mainflux.Env(envSecret, defSecret),
Expand All @@ -115,7 +119,7 @@ func loadConfig() config {
}

func connectToDB(cfg config, logger logger.Logger) *sql.DB {
db, err := postgres.Connect(cfg.DBHost, cfg.DBPort, cfg.DBName, cfg.DBUser, cfg.DBPass)
db, err := postgres.Connect(cfg.DBHost, cfg.DBPort, cfg.DBName, cfg.DBUser, cfg.DBPass, cfg.DBSSLMode)
if err != nil {
logger.Error(fmt.Sprintf("Failed to connect to postgres: %s", err))
os.Exit(1)
Expand Down
13 changes: 12 additions & 1 deletion docs/getting-started.md
Expand Up @@ -465,6 +465,17 @@ By default gRPC communication is not secure.

### Server configuration

### Securing PostgreSQL connections

By default, Mainflux will connect to Postgres using insecure transport.
If a secured connection is required, you can select the SSL mode.

`MF_USERS_DB_SSL_MODE` the SSL connection mode for Users.

`MF_THINGS_DB_SSL_MODE` the SSL connection mode for Things.

Currently supported modes are: `disabled` and `required`

#### Users

If either the cert or key is not set, the server will use insecure transport.
Expand All @@ -491,4 +502,4 @@ If you wish to secure the gRPC connection to `things` and `users` services you m

#### Things

`MF_THINGS_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the service will fail to start up.
`MF_THINGS_CA_CERTS` - the path to a file that contains the CAs in PEM format. If not set, the default connection will be insecure. If it fails to read the file, the service will fail to start up.
38 changes: 20 additions & 18 deletions things/README.md
Expand Up @@ -17,23 +17,24 @@ The service is configured using the environment variables presented in the
following table. Note that any unset variables will be replaced with their
default values.

| Variable | Description | Default |
|-----------------------|-------------------------------------------------|----------------|
| MF_THINGS_LOG_LEVEL | Log level for Things (debug, info, warn, error) | error |
| MF_THINGS_DB_HOST | Database host address | localhost |
| MF_THINGS_DB_PORT | Database host port | 5432 |
| MF_THINGS_DB_USER | Database user | mainflux |
| MF_THINGS_DB_PASS | Database password | mainflux |
| MF_THINGS_DB | Name of the database used by the service | things |
| MF_THINGS_CA_CERTS | Path to trusted CAs in PEM format | |
| MF_THINGS_CACHE_URL | Cache database URL | localhost:6379 |
| MF_THINGS_CACHE_PASS | Cache database password | |
| MF_THINGS_CACHE_DB | Cache instance that should be used | 0 |
| MF_THINGS_HTTP_PORT | Things service HTTP port | 8180 |
| MF_THINGS_GRPC_PORT | Things service gRPC port | 8181 |
| MF_THINGS_SERVER_CERT | Path to server certificate in pem format | 8181 |
| MF_THINGS_SERVER_KEY | Path to server key in pem format | 8181 |
| MF_USERS_URL | Users service URL | localhost:8181 |
| Variable | Description | Default |
|-----------------------|--------------------------------------------------|----------------|
| MF_THINGS_LOG_LEVEL | Log level for Things (debug, info, warn, error) | error |
| MF_THINGS_DB_HOST | Database host address | localhost |
| MF_THINGS_DB_PORT | Database host port | 5432 |
| MF_THINGS_DB_USER | Database user | mainflux |
| MF_THINGS_DB_PASS | Database password | mainflux |
| MF_THINGS_DB | Name of the database used by the service | things |
| MF_THINGS_DB_SSL_MODE | Database connection SSL mode (disable or require)| disable |
| MF_THINGS_CA_CERTS | Path to trusted CAs in PEM format | |
| MF_THINGS_CACHE_URL | Cache database URL | localhost:6379 |
| MF_THINGS_CACHE_PASS | Cache database password | |
| MF_THINGS_CACHE_DB | Cache instance that should be used | 0 |
| MF_THINGS_HTTP_PORT | Things service HTTP port | 8180 |
| MF_THINGS_GRPC_PORT | Things service gRPC port | 8181 |
| MF_THINGS_SERVER_CERT | Path to server certificate in pem format | 8181 |
| MF_THINGS_SERVER_KEY | Path to server key in pem format | 8181 |
| MF_USERS_URL | Users service URL | localhost:8181 |

## Deployment

Expand All @@ -56,6 +57,7 @@ services:
MF_THINGS_DB_USER: [Database user]
MF_THINGS_DB_PASS: [Database password]
MF_THINGS_DB: [Name of the database used by the service]
MF_THINGS_DB_SSL_MODE: [SSL mode to connect to the database with]
MF_THINGS_CA_CERTS: [Path to trusted CAs in PEM format]
MF_THINGS_CACHE_URL: [Cache database URL]
MF_THINGS_CACHE_PASS: [Cache database password]
Expand Down Expand Up @@ -83,7 +85,7 @@ make things
make install

# set the environment variables and run the service
MF_THINGS_LOG_LEVEL=[Things log level] MF_THINGS_DB_HOST=[Database host address] MF_THINGS_DB_PORT=[Database host port] MF_THINGS_DB_USER=[Database user] MF_THINGS_DB_PASS=[Database password] MF_THINGS_DB=[Name of the database used by the service] MF_HTTP_ADAPTER_CA_CERTS=[Path to trusted CAs in PEM format] MF_THINGS_CACHE_URL=[Cache database URL] MF_THINGS_CACHE_PASS=[Cache database password] MF_THINGS_CACHE_DB=[Cache instance that should be used] MF_THINGS_HTTP_PORT=[Service HTTP port] MF_THINGS_GRPC_PORT=[Service gRPC port] MF_USERS_URL=[Users service URL] MF_THINGS_SERVER_CERT=[Path to server certificate] MF_THINGS_SERVER_KEY=[Path to server key] $GOBIN/mainflux-things
MF_THINGS_LOG_LEVEL=[Things log level] MF_THINGS_DB_HOST=[Database host address] MF_THINGS_DB_PORT=[Database host port] MF_THINGS_DB_USER=[Database user] MF_THINGS_DB_PASS=[Database password] MF_THINGS_DB=[Name of the database used by the service] MF_THINGS_DB_SSL_MODE=[SSL mode to connect to the database with] MF_HTTP_ADAPTER_CA_CERTS=[Path to trusted CAs in PEM format] MF_THINGS_CACHE_URL=[Cache database URL] MF_THINGS_CACHE_PASS=[Cache database password] MF_THINGS_CACHE_DB=[Cache instance that should be used] MF_THINGS_HTTP_PORT=[Service HTTP port] MF_THINGS_GRPC_PORT=[Service gRPC port] MF_USERS_URL=[Users service URL] MF_THINGS_SERVER_CERT=[Path to server certificate] MF_THINGS_SERVER_KEY=[Path to server key] $GOBIN/mainflux-things
```

Setting `MF_THINGS_CA_CERTS` expects a file in PEM format of trusted CAs. This will enable TLS against the Users gRPC endpoint trusting only those CAs that are provided.
Expand Down
4 changes: 2 additions & 2 deletions things/postgres/init.go
Expand Up @@ -18,8 +18,8 @@ import (
// Connect creates a connection to the PostgreSQL instance and applies any
// unapplied database migrations. A non-nil error is returned to indicate
// failure.
func Connect(host, port, name, user, pass string) (*sql.DB, error) {
url := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=disable", host, port, user, name, pass)
func Connect(host, port, name, user, pass, sslMode string) (*sql.DB, error) {
url := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s", host, port, user, name, pass, sslMode)

db, err := sql.Open("postgres", url)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion things/postgres/setup_test.go
Expand Up @@ -60,7 +60,7 @@ func TestMain(m *testing.M) {
log.Fatalf("Could not connect to docker: %s", err)
}

if db, err = postgres.Connect("localhost", port, "test", "test", "test"); err != nil {
if db, err = postgres.Connect("localhost", port, "test", "test", "test", "disable"); err != nil {
log.Fatalf("Could not setup test DB connection: %s", err)
}
defer db.Close()
Expand Down
30 changes: 16 additions & 14 deletions users/README.md
Expand Up @@ -16,19 +16,20 @@ The service is configured using the environment variables presented in the
following table. Note that any unset variables will be replaced with their
default values.

| Variable | Description | Default |
|----------------------|-------------------------------------------------|--------------|
| MF_USERS_LOG_LEVEL | Log level for Users (debug, info, warn, error) | error |
| MF_USERS_DB_HOST | Database host address | localhost |
| MF_USERS_DB_PORT | Database host port | 5432 |
| MF_USERS_DB_USER | Database user | mainflux |
| MF_USERS_DB_PASSWORD | Database password | mainflux |
| MF_USERS_DB | Name of the database used by the service | users |
| MF_USERS_HTTP_PORT | Users service HTTP port | 8180 |
| MF_USERS_GRPC_PORT | Users service gRPC port | 8181 |
| MF_USERS_SERVER_CERT | Path to server certificate in pem format | |
| MF_USERS_SERVER_KEY | Path to server key in pem format | |
| MF_USERS_SECRET | String used for signing tokens | users |
| Variable | Description | Default |
|----------------------|--------------------------------------------------|--------------|
| MF_USERS_LOG_LEVEL | Log level for Users (debug, info, warn, error) | error |
| MF_USERS_DB_HOST | Database host address | localhost |
| MF_USERS_DB_PORT | Database host port | 5432 |
| MF_USERS_DB_USER | Database user | mainflux |
| MF_USERS_DB_PASSWORD | Database password | mainflux |
| MF_USERS_DB | Name of the database used by the service | users |
| MF_USERS_DB_SSL_MODE | Database connection SSL mode (disable or require)| disable |
| MF_USERS_HTTP_PORT | Users service HTTP port | 8180 |
| MF_USERS_GRPC_PORT | Users service gRPC port | 8181 |
| MF_USERS_SERVER_CERT | Path to server certificate in pem format | |
| MF_USERS_SERVER_KEY | Path to server key in pem format | |
| MF_USERS_SECRET | String used for signing tokens | users |

## Deployment

Expand All @@ -51,6 +52,7 @@ services:
MF_USERS_DB_USER: [Database user]
MF_USERS_DB_PASS: [Database password]
MF_USERS_DB: [Name of the database used by the service]
MF_USERS_DB_SSL_MODE: [SSL mode to connect to the database with]
MF_USERS_HTTP_PORT: [Service HTTP port]
MF_USERS_GRPC_PORT: [Service gRPC port]
MF_USERS_SECRET: [String used for signing tokens]
Expand All @@ -73,7 +75,7 @@ make users
make install

# set the environment variables and run the service
MF_USERS_LOG_LEVEL=[Users log level] MF_USERS_DB_HOST=[Database host address] MF_USERS_DB_PORT=[Database host port] MF_USERS_DB_USER=[Database user] MF_USERS_DB_PASS=[Database password] MF_USERS_DB=[Name of the database used by the service] MF_USERS_HTTP_PORT=[Service HTTP port] MF_USERS_GRPC_PORT=[Service gRPC port] MF_USERS_SECRET=[String used for signing tokens] MF_USERS_SERVER_CERT=[Path to server certificate] MF_USERS_SERVER_KEY=[Path to server key] $GOBIN/mainflux-users
MF_USERS_LOG_LEVEL=[Users log level] MF_USERS_DB_HOST=[Database host address] MF_USERS_DB_PORT=[Database host port] MF_USERS_DB_USER=[Database user] MF_USERS_DB_PASS=[Database password] MF_USERS_DB=[Name of the database used by the service] MF_USERS_DB_SSL_MODE=[SSL mode to connect to the database with] MF_USERS_HTTP_PORT=[Service HTTP port] MF_USERS_GRPC_PORT=[Service gRPC port] MF_USERS_SECRET=[String used for signing tokens] MF_USERS_SERVER_CERT=[Path to server certificate] MF_USERS_SERVER_KEY=[Path to server key] $GOBIN/mainflux-users
```

## Usage
Expand Down
5 changes: 2 additions & 3 deletions users/postgres/init.go
Expand Up @@ -18,9 +18,8 @@ import (
// Connect creates a connection to the PostgreSQL instance and applies any
// unapplied database migrations. A non-nil error is returned to indicate
// failure.
func Connect(host, port, name, user, pass string) (*sql.DB, error) {
t := "host=%s port=%s user=%s dbname=%s password=%s sslmode=disable"
url := fmt.Sprintf(t, host, port, user, name, pass)
func Connect(host, port, name, user, pass, sslMode string) (*sql.DB, error) {
url := fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=%s", host, port, user, name, pass, sslMode)

db, err := sql.Open("postgres", url)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion users/postgres/setup_test.go
Expand Up @@ -53,7 +53,7 @@ func TestMain(m *testing.M) {
log.Fatalf("Could not connect to docker: %s", err)
}

if db, err = postgres.Connect("localhost", port, "test", "test", "test"); err != nil {
if db, err = postgres.Connect("localhost", port, "test", "test", "test", "disable"); err != nil {
log.Fatalf("Could not setup test DB connection: %s", err)
}
defer db.Close()
Expand Down

0 comments on commit eb38c36

Please sign in to comment.