Skip to content

Commit

Permalink
Remove sops decrypting, receive secrets as environment variables (#8)
Browse files Browse the repository at this point in the history
This is a follow up to RMI/terraform#1, it removes the `sops` dependency from our binaries and moves it into our terraform/Azure secrets configuration. Makes local dev more straightforward and improves cold start times.

Signed-off-by: Brandon Sprague <brandon@sprague.mx>
  • Loading branch information
bcspragu authored Oct 2, 2023
1 parent 22d48ac commit e6e210c
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 2,054 deletions.
7 changes: 0 additions & 7 deletions .sops.yaml

This file was deleted.

46 changes: 8 additions & 38 deletions cmd/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,16 @@ The Credential Server serves the User Service, which is defined in an [OpenAPI 3

Make sure you have [Bazel](https://bazel.build/) installed. For more detailed instructions on some of the tools we use and how we use them, check out the [Silicon Ally Developer Handbook](https://siliconally.getoutline.com/s/d984f195-3e5e-410f-bce8-63676496661f).

Once that's done, you'll either need access to the sops-encrypted `cmd/server/configs/secrets/local.enc.json` file or otherwise replace it with your own. If you have access and are logged in with Azure, you can view this file with `sops cmd/server/configs/secrets/local.enc.json`. Check the [Developer Handbook](https://siliconally.getoutline.com/s/d984f195-3e5e-410f-bce8-63676496661f#h-sops) for more details.

If you don't have access and you're creating your own, it should contain the contents:

```json
{
"auth_private_key": {
"id": "some-id",
"data": "-----BEGIN PRIVATE KEY-----\n[ ... the private key ...]\n-----END PRIVATE KEY-----"
},
"azure_ad": {
"tenant_name": "...",
"user_flow": "B2C_1_...",
"client_id": "11111111-2222-3333-4444-555555555555",
"tenant_id": "00000000-9999-8888-7777-666666666666"
}
}
```

The `azure_ad` section is only required if `use_local_jwts` is false. The `auth_private_key.data` field is the Ed25519 private key used for JWT signing (and the public key is used for validation in the `testcreds` endpoint). To generate a key you can run:

```bash
bazel run //scripts:run_keygen
```

Which will create `test_server.{pub,key}` files in the root of the project. From there, it can be copied into the sops file by running `sops cmd/server/configs/secrets/local.enc.json`.

If you don't do this, you'll get an error like:
Once that's done, make sure the `cmd/server/configs/local.conf` is relevant for your setup. Specifically:

```
failed to decrypt secrets: failed to decrypt file: Failed to read "cmd/server/configs/secrets/local.enc.json": open cmd/server/configs/secrets/local.enc.json: no such file or directory
```

or

```
failed to decrypt secrets: failed to decrypt file: Error getting data key: 0 successful groups required, got 0
```
- `secret_azure_ad_*` configuration parameters are only required if `use_local_jwts` is false
- `secret_auth_private_key_data` is the Ed25519 private key used for JWT signing (and the public key is used for validation in the `testcreds` endpoint).
- To generate a new key you can run:
```bash
bazel run //scripts:run_keygen
```

when you try to run the server.
Which will create `test_server.{pub,key}` files in the root of the project. From there it can be copied into the config, be careful to replace newlines with `\n`.

### Running the Credential Server

Expand Down
1 change: 0 additions & 1 deletion cmd/server/configs/dev.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
env dev
allowed_cors_origins https://*.dev.rmi.siliconally.dev
sops_path /configs/secrets/dev.enc.json

port 80

Expand Down
9 changes: 8 additions & 1 deletion cmd/server/configs/local.conf
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
env local
allowed_cors_origins http://localhost:3000
sops_path cmd/server/configs/secrets/local.enc.json

use_local_jwts true
enable_credential_test_api true

allowed_domains siliconally.org,rmi.org

secret_auth_private_key_id 2023-08-11
secret_auth_private_key_data -----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEINj77iKqwAKJHb0I0XVr8OhvQMpO6SVkmCGlNb9epwUO\n-----END PRIVATE KEY-----

secret_azure_ad_tenant_name rmiauthlocal
secret_azure_ad_user_flow B2C_1_susi_local
secret_azure_ad_client_id 2d77a4a9-b7be-4451-ad47-c151d8b6c05f
secret_azure_ad_tenant_id 1bdaca90-dd54-43ff-a444-ef08988a59fe
32 changes: 0 additions & 32 deletions cmd/server/configs/secrets/dev.enc.json

This file was deleted.

32 changes: 0 additions & 32 deletions cmd/server/configs/secrets/local.enc.json

This file was deleted.

29 changes: 21 additions & 8 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,22 @@ func run(args []string) error {

useLocalJWTs = fs.Bool("use_local_jwts", false, "If true, expect source JWTs to be self-signed, instead of from Azure B2C")

sopsPath = fs.String("sops_path", "", "Path to the sops-formatted file containing sensitive credentials to be decrypted at runtime.")

enableCredTest = fs.Bool("enable_credential_test_api", false, "If true, enables the credential testing API, which returns if credentials are valid")

cookieDomain = fs.String("cookie_domain", "", "Domain to return in the cookie response")

allowedDomains flagext.StringList
allowedCORSOrigins flagext.StringList
minLogLevel zapcore.Level = zapcore.WarnLevel

// Secrets
authKeyID = fs.String("secret_auth_private_key_id", "", "Key ID (kid) of the JWT tokens to generate")
authKeyData = fs.String("secret_auth_private_key_data", "", "PEM-encoded Ed25519 private key to sign JWT tokens with, contains literal \\n characters that will need to be replaced before parsing")

azureADTenantName = fs.String("secret_azure_ad_tenant_name", "", "The name of the tenant user tokens should come from")
azureADUserFlow = fs.String("secret_azure_ad_user_flow", "", "The user flow that users are using to sign in/sign up")
azureADClientID = fs.String("secret_azure_ad_client_id", "", "The client ID the users are authenticating against")
azureADTenantID = fs.String("secret_azure_ad_tenant_id", "", "The ID of the tenant user tokens should come from")
)
fs.Var(&allowedDomains, "allowed_domains", "A comma-separated list of domains that are allowed to get valid credentials")
fs.Var(&allowedCORSOrigins, "allowed_cors_origins", "A comma-separated list of CORS origins to allow traffic from")
Expand All @@ -99,10 +106,6 @@ func run(args []string) error {
name: "env",
val: env,
},
{
name: "sops_path",
val: sopsPath,
},
}
if err := checkFlags(reqFlags); err != nil {
return err
Expand All @@ -126,8 +129,18 @@ func run(args []string) error {
}
}

logger.Info("Loading sops secrets", zap.String("sops_path", *sopsPath))
sec, err := secrets.Load(*sopsPath)
sec, err := secrets.Load(&secrets.RawConfig{
AuthSigningKey: &secrets.RawAuthSigningKey{
ID: *authKeyID,
Data: *authKeyData,
},
AzureAD: &secrets.RawAzureAD{
TenantName: *azureADTenantName,
UserFlow: *azureADUserFlow,
ClientID: *azureADClientID,
TenantID: *azureADTenantID,
},
})
if err != nil {
return fmt.Errorf("failed to decrypt secrets: %w", err)
}
Expand Down
Loading

0 comments on commit e6e210c

Please sign in to comment.