diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3b8f668..2eb8abe 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -54,7 +54,7 @@ jobs: aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws_region: "sa-east-1" source: '_build/prod/*.tar.gz' - dest: 's3://${{ secrets.S3_DIST_URL }}/dist/calori/calori-${CALORI_VERSION}.tar.gz' + dest: 's3://calori-${{ secrets.CLOUD_ENV_NAME }}-distribution/dist/calori/calori-${CALORI_VERSION}.tar.gz' - name: Copy a version file to the s3 version folder uses: prewk/s3-cp-action@v2 @@ -63,4 +63,4 @@ jobs: aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws_region: "sa-east-1" source: 'current.json' - dest: 's3://${{ secrets.S3_DIST_URL }}/versions/calori/prod/current.json' + dest: 's3://calori-${{ secrets.CLOUD_ENV_NAME }}-distribution/versions/calori/${{ secrets.CLOUD_ENV_NAME }}/current.json' diff --git a/README.md b/README.md index 8d8da26..70b2baa 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Create an SSH key pair named, e. g. `calori-web-ec2` by visiting the [AWS Key Pa Ensure you have access to the following secrets for storage in AWS Secrets Manager: - CALORI_SECRET_KEY_BASE - - ERLANG_COOKIE + - CALORI_ERLANG_COOKIE ### 3. CALORI_PHX_HOST Configuration @@ -54,7 +54,7 @@ Wait for the environment to be created. Afterward, update the variables in the * ```bash # Update the secrets CALORI_SECRET_KEY_BASE=xxxxxxxxxx -ERLANG_COOKIE=xxxxxxxxxx +CALORI_ERLANG_COOKIE=xxxxxxxxxx ``` Additionally, create the TLS certificates for the OTP distribution using the [Deployex app](https://github.com/thiagoesteves/deployex?tab=readme-ov-file#enhancing-otp-distribution-security-with-mtls) @@ -170,6 +170,15 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot sudo certbot --nginx ``` +Nginx will automatically generate certificates and modify your configuration files during installation. After installation, verify if the contents of the nginx configuration file match those specified in the original [nginx file ](devops/terraform/modules/standard-account/cloud-config.tpl). If any discrepancies are found, edit the file accordingly and restart Nginx to apply the changes. + +```bash +sudo su +vi /etc/nginx/sites-available/default +# modify and save file +systemctl reload nginx +``` + The comands above will modify nginx file for the correct routing. Once it is all set, you need to check if the [runtime.exs](apps/calori/config/runtime.exs) is pointing to the correct SCHEME/HOST/PORT, e. g.: ```elixir diff --git a/devops/terraform/environments/prod/main_example.tf_ b/devops/terraform/environments/prod/main_example.tf_ index cc8cec5..d87c8fb 100644 --- a/devops/terraform/environments/prod/main_example.tf_ +++ b/devops/terraform/environments/prod/main_example.tf_ @@ -9,4 +9,5 @@ module "standard_account" { source = "../../modules/standard-account" account_name = "stage" server_dns = "example.com" + deployex_dns = "deployex.example.com" } diff --git a/devops/terraform/modules/standard-account/cloud-config.tpl b/devops/terraform/modules/standard-account/cloud-config.tpl index 0f33a14..b6f8f87 100644 --- a/devops/terraform/modules/standard-account/cloud-config.tpl +++ b/devops/terraform/modules/standard-account/cloud-config.tpl @@ -22,7 +22,7 @@ write_files: # Check if the version was passed as an argument if [ -z "$1" ]; then # If not passed, use the default value - VERSION="0.1.0" + VERSION="0.2.0" else # If passed, use the passed value VERSION="$1" @@ -62,7 +62,7 @@ write_files: echo "Retrieving and saving ......" aws secretsmanager get-secret-value --secret-id calori-${account_name}-otp-tls-ca | jq -r .SecretString > /usr/local/share/ca-certificates/ca.crt aws secretsmanager get-secret-value --secret-id calori-${account_name}-otp-tls-key | jq -r .SecretString > /usr/local/share/ca-certificates/deployex.key - aws secretsmanager get-secret-value --secret-id holidex-${account_name}-otp-tls-key | jq -r .SecretString > /usr/local/share/ca-certificates/calori.key + aws secretsmanager get-secret-value --secret-id calori-${account_name}-otp-tls-key | jq -r .SecretString > /usr/local/share/ca-certificates/calori.key aws secretsmanager get-secret-value --secret-id calori-${account_name}-otp-tls-crt | jq -r .SecretString > /usr/local/share/ca-certificates/deployex.crt aws secretsmanager get-secret-value --secret-id calori-${account_name}-otp-tls-crt | jq -r .SecretString > /usr/local/share/ca-certificates/calori.crt echo "[OK]" @@ -108,31 +108,81 @@ write_files: owner: root:root permissions: "0644" content: | - upstream phoenix { - server 127.0.0.1:4000 max_fails=5 fail_timeout=60s; - } - - server { - server_name ${hostname}; - listen 80; + upstream phoenix { + server 127.0.0.1:4000 max_fails=5 fail_timeout=60s; + } - client_max_body_size 30M; - location / { - allow all; + upstream deployex { + server 127.0.0.1:5001 max_fails=5 fail_timeout=60s; + } - # Proxy Headers - proxy_http_version 1.1; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_set_header X-Cluster-Client-Ip $remote_addr; + server { + listen 80; + server_name calori.com.br deployex.calori.com.br; - # The Important Websocket Bits! - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; + if ($host = calori.com.br) { + return 301 https://$host$request_uri; + } # managed by Certbot - proxy_pass http://phoenix; - } - } + + if ($host = deployex.calori.com.br) { + return 301 https://$host$request_uri; + } # managed by Certbot + + return 404; # managed by Certbot + } + + server { + server_name deployex.calori.com.br; + + client_max_body_size 30M; + location / { + allow all; + + # Proxy Headers + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-Cluster-Client-Ip $remote_addr; + + # The Important Websocket Bits! + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_pass http://deployex; + } + + ssl_certificate /etc/letsencrypt/live/calori.com.br/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/calori.com.br/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot + } + + server { + server_name calori.com.br; + + client_max_body_size 30M; + location / { + allow all; + + # Proxy Headers + proxy_http_version 1.1; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_set_header X-Cluster-Client-Ip $remote_addr; + + # The Important Websocket Bits! + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_pass http://phoenix; + } + + ssl_certificate /etc/letsencrypt/live/calori.com.br/fullchain.pem; # managed by Certbot + ssl_certificate_key /etc/letsencrypt/live/calori.com.br/privkey.pem; # managed by Certbot + include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot + } - path: /etc/systemd/system/deployex.service owner: root:root permissions: "0644" @@ -153,6 +203,9 @@ write_files: Environment=DEPLOYEX_OTP_TLS_CERT_PATH=/usr/local/share/ca-certificates Environment=DEPLOYEX_STORAGE_ADAPTER=s3 Environment=DEPLOYEX_MONITORED_APP_NAME=calori + Environment=DEPLOYEX_PHX_SERVER=true + Environment=DEPLOYEX_PHX_HOST=${deployex_hostname} + Environment=DEPLOYEX_PHX_PORT=5001 ExecStart=/opt/deployex/bin/deployex start StandardOutput=append:/var/log/deployex.log KillMode=process diff --git a/devops/terraform/modules/standard-account/ec2.tf b/devops/terraform/modules/standard-account/ec2.tf index 662a81b..e9068bb 100644 --- a/devops/terraform/modules/standard-account/ec2.tf +++ b/devops/terraform/modules/standard-account/ec2.tf @@ -91,6 +91,7 @@ data "cloudinit_config" "server_config" { content_type = "text/cloud-config" content = templatefile("${path.module}/cloud-config.tpl", { hostname = "${var.server_dns}" + deployex_hostname = "${var.deployex_dns}" log_group_name = aws_cloudwatch_log_group.ec2_instance_logs.name account_name = "${var.account_name}" aws_region = "${var.aws_region}" diff --git a/devops/terraform/modules/standard-account/secrets.tf b/devops/terraform/modules/standard-account/secrets.tf index 0f455ac..b5a95bf 100644 --- a/devops/terraform/modules/standard-account/secrets.tf +++ b/devops/terraform/modules/standard-account/secrets.tf @@ -9,6 +9,13 @@ locals { } } +resource "aws_secretsmanager_secret" "deployex_secrets" { + name = "deployex-${var.account_name}-secrets" + description = "All Deployex Secrets" + recovery_window_in_days = 0 + tags = local.secret_tag +} + resource "aws_secretsmanager_secret" "calori_secrets" { name = "calori-${var.account_name}-secrets" description = "All Calori Secrets" @@ -55,6 +62,7 @@ resource "aws_iam_policy" "calori_secrets_manager_policy" { aws_secretsmanager_secret.calori_otp_tls_ca.arn, aws_secretsmanager_secret.calori_otp_tls_key.arn, aws_secretsmanager_secret.calori_otp_tls_crt.arn, + aws_secretsmanager_secret.deployex_secrets.arn, ], }, ], diff --git a/lib/calori_web/components/core_components.ex b/lib/calori_web/components/core_components.ex index 8f2fc83..f534035 100644 --- a/lib/calori_web/components/core_components.ex +++ b/lib/calori_web/components/core_components.ex @@ -702,7 +702,10 @@ defmodule CaloriWeb.CoreComponents do end slot :logo - slot :link, default: [%{__slot__: :link, inner_block: nil, label: "Home", to: "/home"}] + slot(:link, required: true) do + attr :to, :string + attr :label, :string + end @doc """ Copied/Modified from https://fullstackphoenix.com/tutorials/tailwind-navbar-new-liveview-0-18-components diff --git a/lib/config_provider/aws_secrets_manager.ex b/lib/config_provider/aws_secrets_manager.ex index dfbb56a..9502281 100644 --- a/lib/config_provider/aws_secrets_manager.ex +++ b/lib/config_provider/aws_secrets_manager.ex @@ -46,7 +46,7 @@ defmodule Calori.AwsSecretsManagerProvider do secrets = fetch_aws_secret_id("calori-#{env}-secrets", request_opts) secret_key_base = keyword(:secret_key_base, secrets["CALORI_SECRET_KEY_BASE"]) - erlang_cookie = secrets["ERLANG_COOKIE"] |> String.to_atom() + erlang_cookie = secrets["CALORI_ERLANG_COOKIE"] |> String.to_atom() # Config Erlang Cookie if the node exist node = :erlang.node()