From b3f3ec290d82ac30a6152dae02d45aff41962036 Mon Sep 17 00:00:00 2001 From: Geoffrey Wilson Date: Tue, 22 Oct 2024 14:49:42 -0400 Subject: [PATCH] Add SSL support to astral api server (#53) * Add SSL support to astral api server --- Dockerfile | 2 +- README.md | 30 ++++++++++++++++++----- bin/http.sh | 2 ++ bin/ssl.sh | 5 ++++ cert/astral.csr | 28 ++++++++++++++++++++++ cert/astral.key | 52 ++++++++++++++++++++++++++++++++++++++++ cert/astral.pem | 31 ++++++++++++++++++++++++ lib/tasks/configure.rake | 46 ++++++++++++++++++++++++----------- 8 files changed, 175 insertions(+), 21 deletions(-) create mode 100755 bin/http.sh create mode 100755 bin/ssl.sh create mode 100644 cert/astral.csr create mode 100644 cert/astral.key create mode 100644 cert/astral.pem diff --git a/Dockerfile b/Dockerfile index 3d941b3..d63d76e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -55,4 +55,4 @@ USER rails:rails # Start the server by default, this can be overwritten at runtime EXPOSE 3000 # Start the server -CMD ["bin/rails", "server", "-b", "0.0.0.0"] \ No newline at end of file +CMD ["bin/http.sh"] \ No newline at end of file diff --git a/README.md b/README.md index 04fe05a..6a143ab 100644 --- a/README.md +++ b/README.md @@ -72,21 +72,37 @@ file. Per-environment settings in the config file(development, test, production) will override the shared values for that type. ## mTLS connections -Astral can connect to Vault with mTLS. Just -set the following values in `config/astral.yml`: +Astral can be run as an SSL service and can communicate with Vault via SSL. +Just set the following values in `config/astral.yml` (or environment) to +encrypt Astral-to-Vault : ``` vault_ssl_cert: vault_ssl_client_cert: vault_ssl_client_key: ``` -A self-signed server cert for Vault can be generated with the following -command: + +A self-signed server cert for Vault, Astral, and the OIDC provider can be +generated with the following command, and initial placeholder certs are already provided. ``` rake configure:ssl ``` -To use SSL in the devcontainer, edit `.devcontainer/docker-compose.yml` so -that the `app` service has `VAULT_ADDRESS` of `https://vault:8443`. +To use Vault SSL in the devcontainer, edit +`.devcontainer/docker-compose.yml` so that the `app` service has +`VAULT_ADDRESS` of `https://vault:8443`. Client certs can also be +configured -- in which case Vault needs to supplied with a CA for +peer verification. + +To use Astral with SSL in production, provide the necessary +environment (ASTRAL_SSL_CERT, ASTRAL_SSL_KEY) to the container +environment, and use the `bin/ssl.sh` startup command. Eg: +``` +docker run -p 3000:3000 \ +-e ASTRAL_SSL_CERT=/certs/cert.pem \ +-e ASTRAL_SSL_KEY=/certs/key.key \ +-v certs:/certs:cached \ +astral:latest bin/ssl.sh +``` ## OIDC configuration The OIDC modules allow the assignment of a policy to an OIDC user, by @@ -123,6 +139,8 @@ config/astral.yml). The rails test's configure the OIDC initial user, so if the tests pass, you can invoke the oidc login as follows: +To use SSL in production, provide the necessary environment (SSL_CERT, SSL_KEY) to +the container environment, and use the `bin/ssl.sh` startup command. Eg: ``` export VAULT_ADDR=http://127.0.0.1:8200; vault login -method=oidc ``` diff --git a/bin/http.sh b/bin/http.sh new file mode 100755 index 0000000..98c97d4 --- /dev/null +++ b/bin/http.sh @@ -0,0 +1,2 @@ +#! /bin/sh +bin/rails s -b 0.0.0.0 diff --git a/bin/ssl.sh b/bin/ssl.sh new file mode 100755 index 0000000..0b98453 --- /dev/null +++ b/bin/ssl.sh @@ -0,0 +1,5 @@ +#! /bin/sh +ASTRAL_SSL_CERT="${SSL_CERT:-cert/astral.pem}" +ASTRAL_SSL_KEY="${SSL_KEY:-cert/astral.key}" + +bin/rails s -b "ssl://0.0.0.0:3000?key=${ASTRAL_SSL_KEY}&cert=${ASTRAL_SSL_CERT}" diff --git a/cert/astral.csr b/cert/astral.csr new file mode 100644 index 0000000..728b54e --- /dev/null +++ b/cert/astral.csr @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIEvDCCAqQCAQAwUzELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIG +A1UEBwwLU3ByaW5nZmllbGQxDDAKBgNVBAoMA0RpczEPMA0GA1UEAwwGYXN0cmFs +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnikPRYuwiWfHxN2V8/NP +SEhztM9m76gMfKoFQMdDLLLIBSicFxNFRJogkcWGnkEGIWNCQeXpFuihl3CWXmdo +ubqhHpVjcoG5iGXBDaDCSaImkFCmHNuetTkuIoM+UWZRlM7lkic5T1Kxy5Fr1dDd +F0vLNJ5uEBcJ5eufs8YaodzWzAk7HbJ1Du0Y3lS3cnEcEDFOSut2nT/fJyGKi1eA +YGm/NnBrDP5zto3XCxjXiLxIoZxLXJj/9Fzjs2L4j/FeaxTgTa7qzmAtxZcxnm81 +nO8jOzsEeCmLcp5oMJQPOJ+5GL4Lq4TDjBxc/IVhHpCRMWhvCvoDPBqQgA1TFVpx +eRvlU4N4cncbk7X7AzUJWZXhFWGbjJRqRlzTl7Gjs7fTvmjQEMNxZVD5F72/AeJo +Wit0MgBZ5sbssbNtS8F4WrujI0ZPWM2KhNCVdUjS9E9UUOu+CIr7dgdiZDe/2rbv +Njb+Gpbj8iBP18osOoCfAsEnyQpODfsO5c5IX/ubEWzsdQETE17eF5uk/+ZMQj+2 +f625pmn+uzDPjEHLTxKILHuJcPySyeRktO+5qKLnKqUq5VaBEaMfJ8jKjbIDPAPw +VLBp2NUzZgZBeXmwOvLtAFWRBXobX8hW3KRqlZ0FAMDuDRrsur9JZTMOteSrm7Sv +1wvEQ5XYav3XultxFqeH5XkCAwEAAaAkMCIGCSqGSIb3DQEJDjEVMBMwEQYDVR0R +BAowCIIGYXN0cmFsMA0GCSqGSIb3DQEBCwUAA4ICAQB9rIUacRyzxbDgB2OBsfNr +9VIe2GTjZBEEz7DAVk3LI65GhhlcAfHi2ZNmeDxtsG21zAkTnmj5iF4m6g7YbDe6 +7jVh3NkI36bvLNg8nElqmDeFv0detUxCCaPzwJJo/jdPHyPDIGdvz2J2Wja+txiL +2PMp45i8SdESaiG7Y3GZwCN5hHYSEPMX0QkK30rYUdbreMWxrBnsXaPixKD1jXMC +ZkW4XhjPP4j650x0i2SFDdRKa9aTOcX4TwoewTw5ok+hXIvmRrIVMBUbGyP5fZHA +FSWZgX6iLOC58Lud2Xkbiex7ydIp/gaUAQ6JLtnw0hUJr77JxJU5WaC1Jn3Sm26p +FFnKcBsa10oFlUUyehVaaO6qWV7+SZ//7s2FvwNI765cjLcyBbdf2iimhbFiNvOh +1YgOnJ3BwpOa+AxPWZyUI3Iz2VtQnmHauQ2XqwfgHSj1gxKR+t05SgHFa28k4KAJ +mWFecL+rSeN9nvrRmzjQOhIgVw9ljMzXhcEJFjO1Xf9TKUTfrqNEoPqIAdAbXJhX +rByaS/NyICOMT5fSY+UCs1qbC7FpujRRKyt8R10bBXvUXSB5eMOdRbf5R11lalX9 +xgnTW9w9TAdaZglkt6M1AXesh8F3F11lMtrIy7BFdcxTaPbPMui3zV3hNd7b64Vc ++qHZal53OFX+CAApKa4MSQ== +-----END CERTIFICATE REQUEST----- diff --git a/cert/astral.key b/cert/astral.key new file mode 100644 index 0000000..82f3c66 --- /dev/null +++ b/cert/astral.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +2HQc6yP5r2gYlP78sFptd09YRT8oCA== +-----END PRIVATE KEY----- diff --git a/cert/astral.pem b/cert/astral.pem new file mode 100644 index 0000000..726bfd5 --- /dev/null +++ b/cert/astral.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFSTCCAzGgAwIBAgIUIOIfpkyG8YDizn/N7dOZl1etxpgwDQYJKoZIhvcNAQEL +BQAwUzELMAkGA1UEBhMCVVMxDzANBgNVBAgMBkRlbmlhbDEUMBIGA1UEBwwLU3By +aW5nZmllbGQxDDAKBgNVBAoMA0RpczEPMA0GA1UEAwwGYXN0cmFsMB4XDTI0MTAy +MjE4MzExNFoXDTI1MTAyMjE4MzExNFowUzELMAkGA1UEBhMCVVMxDzANBgNVBAgM +BkRlbmlhbDEUMBIGA1UEBwwLU3ByaW5nZmllbGQxDDAKBgNVBAoMA0RpczEPMA0G +A1UEAwwGYXN0cmFsMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnikP +RYuwiWfHxN2V8/NPSEhztM9m76gMfKoFQMdDLLLIBSicFxNFRJogkcWGnkEGIWNC +QeXpFuihl3CWXmdoubqhHpVjcoG5iGXBDaDCSaImkFCmHNuetTkuIoM+UWZRlM7l +kic5T1Kxy5Fr1dDdF0vLNJ5uEBcJ5eufs8YaodzWzAk7HbJ1Du0Y3lS3cnEcEDFO +Sut2nT/fJyGKi1eAYGm/NnBrDP5zto3XCxjXiLxIoZxLXJj/9Fzjs2L4j/FeaxTg +Ta7qzmAtxZcxnm81nO8jOzsEeCmLcp5oMJQPOJ+5GL4Lq4TDjBxc/IVhHpCRMWhv +CvoDPBqQgA1TFVpxeRvlU4N4cncbk7X7AzUJWZXhFWGbjJRqRlzTl7Gjs7fTvmjQ +EMNxZVD5F72/AeJoWit0MgBZ5sbssbNtS8F4WrujI0ZPWM2KhNCVdUjS9E9UUOu+ +CIr7dgdiZDe/2rbvNjb+Gpbj8iBP18osOoCfAsEnyQpODfsO5c5IX/ubEWzsdQET +E17eF5uk/+ZMQj+2f625pmn+uzDPjEHLTxKILHuJcPySyeRktO+5qKLnKqUq5VaB +EaMfJ8jKjbIDPAPwVLBp2NUzZgZBeXmwOvLtAFWRBXobX8hW3KRqlZ0FAMDuDRrs +ur9JZTMOteSrm7Sv1wvEQ5XYav3XultxFqeH5XkCAwEAAaMVMBMwEQYDVR0RBAow +CIIGYXN0cmFsMA0GCSqGSIb3DQEBCwUAA4ICAQAjvn25pMxkwj8dLB0IdSXUYZXE +eBKigf0xZnvOXvDKMd6o2o90n0HbNv1WaZLOQJtrwbyn0B/MKEDVSHRcjvJinYfv +Z7TzPPE7+XQYozBNZjBu+mjtD2a6YKnjsJ8MFeNZYVK8Fp5+h6fG3JrPiZjakLwQ +g0p7jZWIZA5AFsBwLw6gAYCg2S97FQL9dG2PMDW2qtokdS+bzm5EUNZqlHfDgJdG +DaRi1WLw0AK6/Dfz/x2dVoN/RA602jtoNJq1JxktUIMTjbvwU6MAmIxi2a2GxIQZ +dYefVQP6Ub5xkgnLkqhgcC/A7HMFAkXK1g93T8iN11ZQLPkoUgWB5CuFGmaXqdKw +GwrrZDVn0slyX4gBdqJPm7i+jXP6PHFcHFU895c8g+T1MZRkXNDpEMpKGQMZ/02n +8/ZQn+aj9fjIo6UhSDd1zESR11q3kvhW26WdpRvOBrxfNEB5Zd9NOV8q9G4v+WLS +OAT4r5Ykde1GZIu5ayPU73XmVuhNVFbkCK/FtuNVJR/lWmF9gNyXJX3r33bySY/v +HmUCufor7SwSSn7KoXEtCGuEILiF6stoMgr6CKP/uL8mTGsyXABlPN1uaN4gLO6e +n9U+ANtcq/+miuadfjldSqoQqHhzRgy/GA24kQ84yQWjAQ9cKaHP3Kk536dWs9RV +TRznVEoy1it0bhIY4w== +-----END CERTIFICATE----- diff --git a/lib/tasks/configure.rake b/lib/tasks/configure.rake index 52fc1ad..0e2df4c 100644 --- a/lib/tasks/configure.rake +++ b/lib/tasks/configure.rake @@ -2,22 +2,40 @@ require "rake" # Rake tasks for making a vault cert namespace :configure do + desc "Make Vault, Astral, and OIDC provider certs" + task ssl: [ :vault_ssl, :astral_ssl, :oidc_provider_ssl ] + desc "Make the server cert for vault" - task :ssl, [ :cert_name ] do |t, args| - cert_name = args[:cert_name] - cert_name = "vault" if cert_name.nil? - sanParam = "subjectAltName=DNS:#{cert_name}" - %x( - openssl req -new -newkey rsa:4096 -nodes \ - -keyout cert/#{cert_name}.key -out cert/#{cert_name}.csr \ - -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=#{cert_name}" \ - -addext #{sanParam} \ + task :vault_ssl do + keygen("vault") + end + + desc "Make the server cert for astral" + task :astral_ssl do + keygen("astral") + end - echo #{sanParam} > /tmp/sanParam - openssl x509 -req -days 365 -in cert/#{cert_name}.csr \ - -signkey cert/#{cert_name}.key \ - -out cert/#{cert_name}.pem -extfile /tmp/sanParam + desc "Make the server cert for the oidc provider" + task :oidc_provider_ssl do + keygen("oidc_provider") + end + + private + + def keygen(name) + san_param_file = "/tmp/san_param_#{name}" + san_param_content = "subjectAltName=DNS:#{name}" + File.write(san_param_file, san_param_content) + %x( + openssl req -new -newkey rsa:4096 -nodes \ + -keyout cert/#{name}.key -out cert/#{name}.csr \ + -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=#{name}" \ + -addext #{san_param_content} + openssl x509 -req -days 365 -in cert/#{name}.csr \ + -signkey cert/#{name}.key \ + -out cert/#{name}.pem \ + -extfile #{san_param_file} ) - puts "SSL key for #{cert_name} created" + puts "SSL key for #{name} created" end end