Skip to content

Commit

Permalink
Updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jezzsantos committed Jan 4, 2025
1 parent 81fca11 commit 4ea234c
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 28 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/deploy-azure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ env:
SOLUTION_PATH: 'src/SaaStack.sln'
DEPLOY_BUILD_CONFIGURATION: 'ReleaseForDeploy'
DOTNET_VERSION: 8.0.302
HOSTEDON: 'HOSTEDONAZURE'
HOSTED_ON: 'HOSTEDONAZURE'

jobs:
build:
Expand All @@ -37,7 +37,7 @@ jobs:
npm ci --cache .npm --prefer-offline
npm run build
- name: Build (Backend) for Deploy
run: dotnet build --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "${{env.SOLUTION_PATH}}" /p:HostingPlatform=${{env.HOSTEDON}}
run: dotnet build --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "${{env.SOLUTION_PATH}}" /p:HostingPlatform=${{env.HOSTED_ON}}
- name: Build WebsiteHost (FrontEnd) for Deploy
run: |
cd src/WebsiteHost/ClientApp
Expand All @@ -51,11 +51,11 @@ jobs:
variables: ${{ toJSON(vars)}}
secrets: ${{ toJSON(secrets)}}
- name: Package (ApiHost1) for Deploy
run: dotnet publish --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "src/ApiHost1/ApiHost1.csproj" --output ".\publish\ApiHost1" /p:HostingPlatform=${{env.HOSTEDON}}
run: dotnet publish --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "src/ApiHost1/ApiHost1.csproj" --output ".\publish\ApiHost1" /p:HostingPlatform=${{env.HOSTED_ON}}
- name: Package (WebsiteHost) for Deploy
run: dotnet publish --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "src/WebsiteHost/WebsiteHost.csproj" --output ".\publish\WebsiteHost" /p:HostingPlatform=${{env.HOSTEDON}}
run: dotnet publish --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "src/WebsiteHost/WebsiteHost.csproj" --output ".\publish\WebsiteHost" /p:HostingPlatform=${{env.HOSTED_ON}}
- name: Package (AzureFunctions) for Deploy
run: dotnet publish --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "src/AzureFunctions.Api.WorkerHost/AzureFunctions.Api.WorkerHost.csproj" --output ".\publish\AzureFunctions.Api.WorkerHost" /p:HostingPlatform=${{env.HOSTEDON}}
run: dotnet publish --configuration ${{env.DEPLOY_BUILD_CONFIGURATION}} "src/AzureFunctions.Api.WorkerHost/AzureFunctions.Api.WorkerHost.csproj" --output ".\publish\AzureFunctions.Api.WorkerHost" /p:HostingPlatform=${{env.HOSTED_ON}}
- name: Upload (ApiHost1) artifacts
uses: actions/upload-artifact@v4
with:
Expand All @@ -72,6 +72,7 @@ jobs:
name: AzureFunctions.Api.WorkerHost
path: ./publish/AzureFunctions.Api.WorkerHost
include-hidden-files: true # HACK: see https://github.com/Azure/azure-functions-dotnet-worker/issues/1240
# TODO: Deploy these artifacts
# deploy:
# runs-on: windows-latest
# timeout-minutes: 30
Expand Down
92 changes: 69 additions & 23 deletions docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@

This document details the basic steps required to deploy your software into a production environment.

A production environment might be in the cloud or on premise. The deployment process is similar, except for the tools used to perform the deployment.
A production environment might be in the cloud or on premise. The deployment process will be similar in either case, except for the tools used to perform the deployment.

By default, this deployment is assumed to take place from a GitHub repository using GitHub Actions. However, you can use any CI/CD tool you prefer, many of the steps below are similar.
By default, this deployment is assumed to take place from a GitHub repository using GitHub Actions.

> However, you can use any CI/CD tool you prefer, many of the steps below will be similar, but will differ based on the toolset you use.
## Automated deployment

The deployment process is automated using GitHub Actions.

This deployment process is defined in the [deploy.yml](../.github/workflows/deploy.yml) file.
This deployment process is defined in the following files:
* [deploy-azure.yml](../.github/workflows/deploy-azure.yml) for deploying to Microsoft Azure.
* [deploy-aws.yml](../.github/workflows/deploy-aws.yml) for deploying to Amazon AWS.

> You can read and understand and reverse engineer these YML files to understand how the deployment process works for your environment or toolset.
Essentially we are deploying the following pieces of infrastructure:
Essentially we are deploying the following pieces of infrastructure in the cloud:
* Azure:
* An Azure App Service for each API Host (i.e., `ApiHost`) for the Backend APIs.
* An Azure App Service for the `WebsiteHost` for the Frontend website.
Expand All @@ -26,16 +32,29 @@ Essentially we are deploying the following pieces of infrastructure:
* An AWS SNS for publishing domain_events to various registered subscribers (i.e., `ApiHost1`).
* An AWS S3 bucket for Blob storage.

To deploy any of these services to the respective cloud provider, we use standard GitHub Actions to perform the deployment.
Each one of these services may require one or more variables/secrets to be defined in the GitHub repository.
To deploy any of these services to the respective cloud provider, we will use standard GitHub Actions to perform the deployment, available from the [GitHub Actions Marketplace](https://github.com/marketplace?type=actions).

## Configuration

Each one of these deployable pieces of infrastructure will likely require production specific configuration, using variables/secrets that must be defined outside the source code.One safe place to store them is in the GitHub repository, categorized for a specific "environment".

We define a deployment "environment" in the GitHub project first, then we define the variables and secrets in that specific environment.

We define an environment in the GitHub project first, then we define the variables and secrets for that environment.
> Unlike, Variables in GitHub (which are only available in a specific environment), Secrets in GitHub can be defined at the organization level, or at the repository level or at the environment level. When reading Secrets, they are combined from Organization, Repository and Environment when read from any GitHub Actions.
The initial list of those variables and secrets are detailed in the `appsettings.json` files of each of the deployable hosts in the solution. They are defined in the `Deploy -> Required -> Keys` sections of the `appsettings.json` files.
The initial list of those variables and secrets is detailed in the `appsettings.json` files of each of the deployable hosts in the solution.

> This list is not inclusive of all other variables that you may want to change for your production environment, this list is the bare minimum that are REQUIRED to be replaced for deployment. If you add other secrets/variables to your GitHub project (using the same naming convention below), they will also overwrite settings found in any `appsettings.json` files in the repository.
Some of these settings have default values already in `appsettings.json`.

For each of these settings (in `appsettings.json` files), we must define an equivalent environment variable or secret in the GitHub project.
Some of these settings will be "required" to be overwritten before being deployed into a production environment, with production environment settings. These settings will not be known at development time, and MUST NEVER be defined in the source code.

Since, adding new configuration settings is common as products evolve, we need a reliable way to mark up settings as being necessarily "required" to be overwritten in a production environment. As opposed to using the default values already defined in the `appsettings.json` files.

To this end, in the `appsettings.json` file, there is section: `Deploy -> Required -> Keys` which declares the settings that MUST be overwritten for deployment to any environment.

> This list is not inclusive of all other variables that you may want to change for your production environment, this list is the bare minimum that are REQUIRED to be replaced for deployment. If you add other secrets/variables to your GitHub project (using the same naming convention below), they will also be automatically applied to any `appsettings.json` files in the repository at deploy time too.
To overwrite any settings in `appsettings.json` at deployment time, we must define an equivalent environment variable or secret in the GitHub project.

The naming convention is to take the fully qualified name in `appsettings.json`, and convert it to uppercase, and replace the following characters: `:`, `-` and `.` with `_`.

Expand All @@ -53,13 +72,17 @@ For example, if you had this setting in `appsettings.json`:
```
The equivalent GitHub variable/secret name of the setting above, would need to be: `APPLICATIONSERVICES_PERSISTENCE_KURRENT_CONNECTIONSTRING`.

## Variables
It is more than likely that at some point in time, during normal development a new setting will be added to the `appsettings.json` file, and the developer may also remember to mark it up as "required" in the `Deploy -> Required -> Keys` section of `appsettings.json`, but the developer may forget to add the equivalent variable/secret ot the GitHib project. In this case, the deployment will detect this problem, and fail the deployment, and the error message will tell you which setting is missing, and how to fix it.

This is one of the safeguards of using the `VariableSubstitution` custom action.

### GitHub environment variables

Most of the required variables defined in the `Deploy -> Required -> Keys` section of `appsettings.json` should be self-explanatory.

Here are ones that might need a little more explanation:
Here are ones that might need further explanation, about their origin and use:

### Operator Whitelist
#### Operator whitelist

Setting name: `HOSTS_ENDUSERSAPI_AUTHORIZATION_OPERATORWHITELIST`

Expand All @@ -70,15 +93,16 @@ This list is populated before the user accounts are registered and when they are

> For user accounts that already exist, they can be promoted by existing operator accounts.
## Secrets
### GitHub secrets

The following MUST be defined as secrets in yor GitHub project, not as environment variables:
The following MUST be defined as secrets in yor GitHub project, NOT as environment variables:

**IMPORTANT**: You MUST generate new random secrets for your deployed services!
> We recommend these are defined in the secrets of the environment, however, they can also be defined at the repository level, or at the organization level.
**IMPORTANT**: You MUST generate new random secrets for your deployed services!
**IMPORTANT**: You MUST never re-use the secrets defined in this repository in your production environment. They are far too well known to anyone who has access to this repository, using them compromises your production environment.

### HMAC Signing Key
#### HMAC signing key

For secrets such as `HOSTS_APIHOST1_HMACAUTHNSECRET` and `HOSTS_ANCILLARYAPI_HMACAUTHNSECRET`:
* Generate a random value using the [HMACSigner.GenerateKey()](https://github.com/jezzsantos/saastack/blob/main/src/Infrastructure.Web.Api.Common/HMACSigner.cs) method.
Expand All @@ -87,7 +111,7 @@ For secrets such as `HOSTS_APIHOST1_HMACAUTHNSECRET` and `HOSTS_ANCILLARYAPI_HMA
**IMPORTANT**: It is vital that all the HMAC signing keys on each deployed host are identical. You can have different values on different hosts, as long as all their client hosts are also updated.

### CSRF secrets
#### CSRF secrets

For the CSRF `HOSTS_WEBSITEHOST_CSRFHMACSECRET` secret
* Generate a new random value using the [CSRFToken.GenerateKey()](https://github.com/jezzsantos/saastack/blob/main/src/Infrastructure.Web.Api.Common/HMACSigner.cs) method as above for HMAC secrets.
Expand All @@ -99,22 +123,44 @@ For the CSRF `HOSTS_WEBSITEHOST_CSRFAESSECRET` secret:

> Note: You can run the unit tests for this class and copy the value of the generated key in the first test.
### SSO
#### SSO

For the `APPLICATIONSERVICES_SSOPROVIDERSSERVICE_SSOUSERTOKENS_AESSECRET` secret:
* Generate a new random value using the [AesEncryptionService.GenerateAesSecret()](https://github.com/jezzsantos/saastack/blob/main/src/Infrastructure.Common/DomainServices/AesEncryptionService.cs) method.

> Note: You can run the unit tests for this class and copy the value of the generated key in the first test.
### JWT Signing Key
#### JWT signing key

For the `HOSTS_IDENTITYAPI_JWT_SIGNINGSECRET` secret:
* Generate a new random value using the [JwtTokenService.GenerateSigningKey()](https://github.com/jezzsantos/saastack/blob/main/src/IdentityInfrastructure/ApplicationServices/JWTTokensService.cs) method.

> Note: You can run the unit tests for this class and copy the value of the generated key in the first test.
## Invoking a deployment
### Additional GitHub secrets and variables

In order to deploy your code to Cloud based infrastructure (such as Azure or AWS) you will be using standard GitHub Actions to perform the deployment.
Most of these actions will require additional configuration with secrets to access your cloud provider and cloud accounts.

For example, when using the `deploy-azure.yml` file, you will need to define login secrets in order to deploy your code to Azure Infrastructure.
You can read about this process and the credentials required to do it in the [Azure Login Action](https://learn.microsoft.com/en-us/azure/app-service/deploy-github-actions?tabs=openid%2Caspnetcore).

For deploying to Azure, (using the `deploy-azure.yml` deployment workflow) you will also need to define the following secrets and variables in your GitHub deployment environment:
* `DEPLOY_AZURE_CLIENT_ID`
* `DEPLOY_AZURE_TENANT_ID`
* `DEPLOY_AZURE_SUBSCRIPTION_ID`

> These are used to automate the deployment to your Azure subscription.
then, you will need these to define the physical components to deploy your code to:
* `DEPLOY_APIHOST1_APP_NAME`
* `DEPLOY_WEBSITEHOST_APP_NAME`
* `DEPLOY_AZUREFUNCTIONS_APP_NAME`

> Note: the prefix `DEPLOY_` groups these settings as distinct from others in the GitHub project.
## Triggering a deployment

The deployment script (`deploy.yml`) is triggered only by a push to the `main` branch, with a specific commit message, that includes the instruction `xxx`.
The deployment script (`deploy-azure.yml` and `deploy-aws.yml`) is triggered only by a push to the `main` branch, with a specific commit message, that includes the instruction `xxx`.

> This is a safety feature to prevent accidental deployments in the course of normal development of your product.
> This is a safety feature to prevent accidental deployments in the course of normal development of your product. This step should be very intentional in environment where you are not practicing "Continuous Deployment".

0 comments on commit 4ea234c

Please sign in to comment.