m-flak / matts

"Matthew's ATS" - Portfolio Project - A fully functional job board! Deploys to Azure and uses Azure Functions.
GNU Affero General Public License v3.0
1 stars 0 forks source link
angular asp-net-core azure azure-container-instances azure-functions csharp docker docker-compose neo4j net7 oauth2 typescript websockets

matts - "Matthew's ATS"

Matthew's ATS is a functional, single-tenant, and cloud-native web application serving as an Applicant Tracking System.

As an employer:

As a job seeker:

Azure Setup

This project consists of two Azure components.

The first is the application itself. It is an Azure Container Instances (ACI) group.

The second is the companion matts.AzFunctions project for Azure Functions used by the application.

ACI Group Managed Identity & Permissions

The ACI Group will need a system assigned managed identity with permissions to access the key vault, app config store, storage account, and the blob container (important!).

The key vault is also used in the GH Action pipeline. A service account will need to be created for your Azure Resource Group. Refer to the project's GitHub Actions folder for more details.

  1. Key Vault Permissions
    KEY VAULT SECRETS USER
  2. App Config Permissions
    APP CONFIGURATION DATA READER
  3. Storage Account Permissions
    READER AND DATA ACCESS
    STORAGE BLOB DATA READER and STORAGE BLOB DELEGATOR
  4. Blob Container Permissions
    STORAGE BLOB DATA OWNER
Container Setup

For the nitty-gritty on the container setup, see the .azure/template.json file. Since ARM is being used instead of docker-compose for deployment, ensure what's in the docker-compose file is mirrored in the ARM template. Each volume for a container will need to be assigned an Azure File Share. It's share per volume, apparently.

These settings need to be in the configuration store. The application will filter by its prefix and the build environment that it was built against. app config keys

The service endpoint of the App Config itself will need to be placed within the appropriate appsettings.json file.

NOTE: This screenshot may not contain everything. Refer to the C# classes within the Configuration folder as well as the json configuration files.

For HTTPS, currently the application utilizes a self-signed certificate. Place a PFX certificate file within the root of the apphttps file share. The DnsName of the cert needs to match the deployment url, which will remain the same after the container group is created, even if the group needs to be deleted due to certain prop changes. If you create one first in Azure Portal, be sure to add together the values for memory and cpu of both containers, so you don't have to delete it before a deployment.

After a successful deployment, the application is accessible at the url attached to the deployment.

Local Dev Environment Setup

DOCKER

Make sure you have Powershell 7.

First Time

As Administrator, run these powershell commands to setup your environment. Once setup, you can start and stop the container to access the application.

If you can't run as admin, change the certstore location to CurrentUser.

# Cert Path Setup
$certsFolder = "$(If ($env:HOME -ne $null) {$env:HOME+'/.devcerts'} Else {$env:USERPROFILE+'\.devcerts'})"
New-Item -Force -ItemType "directory" -Path $certsFolder
$certKeyPath = "$certsFolder\matts-localhost.pfx"

# Create a self-signed Cert
$cert = New-SelfSignedCertificate -DnsName "localhost" -FriendlyName "localhost development certificate" -NotAfter (Get-Date).AddYears(15) -CertStoreLocation "cert:\LocalMachine\My"
$password = Get-Credential -Message 'Enter Password' -UserName 'SSL Certificate'

# Export the self-signed cert
$cert | Export-PfxCertificate -FilePath $certKeyPath -Password $password.Password
$rootCert = $(Import-PfxCertificate -FilePath $certKeyPath -CertStoreLocation 'Cert:\LocalMachine\Root' -Password $password.Password)

# Place your cert's password in an env file for the container
"ASPNETCORE_Kestrel__Certificates__Default__Password=" | Out-File -FilePath docker.development.secret.env -NoNewline
ConvertFrom-SecureString -SecureString $password.Password -AsPlainText | Out-File -FilePath docker.development.secret.env -Append

# Setup the user-secrets stuff
dotnet user-secrets set "Neo4J:User"  "neo4j"
dotnet user-secrets set "Neo4J:Password"  "changeme"
$stream = [IO.MemoryStream]::new([Text.Encoding]::UTF8.GetBytes($(Get-Random).toString()))
$sha = Get-FileHash -InputStream $stream -Algorithm SHA256
$bytes = [byte[]] -split ($sha.Hash -replace '..', '0x$& ')
$key = [Convert]::ToBase64String($bytes)
dotnet user-secrets set "Jwt:SigningKey"  $key
dotnet user-jwts create

# Compose container using the override profile for development
$env:MATTS_DEVCERT_FOLDER = $certsFolder
docker-compose --env-file ./docker.development.env -f docker-compose.yml -f docker-compose.development.yml up -d

Subsequent Rebuilds

This is all that's required once the initial secrets setup & cert generation has been performed.

$certsFolder = "$(If ($env:HOME -ne $null) {$env:HOME+'/.devcerts'} Else {$env:USERPROFILE+'\.devcerts'})"
$env:MATTS_DEVCERT_FOLDER = $certsFolder
docker-compose --env-file ./docker.development.env -f docker-compose.yml -f docker-compose.development.yml up --build matts

NON-DOCKER

You need to have Neo4J setup. Once it's setup, you just start and stop it using Docker Desktop.

First, setup the container...

docker-compose --env-file ./docker.development.env -f docker-compose.yml -f docker-compose.development.yml up neo4j -d

(One time only) Next, you need to setup your secrets:

dotnet user-secrets set "Neo4J:User"  "neo4j"
dotnet user-secrets set "Neo4J:Password"  "changeme"
$stream = [IO.MemoryStream]::new([Text.Encoding]::UTF8.GetBytes($(Get-Random).toString()))
$sha = Get-FileHash -InputStream $stream -Algorithm SHA256
$bytes = [byte[]] -split ($sha.Hash -replace '..', '0x$& ')
$key = [Convert]::ToBase64String($bytes)
dotnet user-secrets set "Jwt:SigningKey"  $key
dotnet user-jwts create

Finally, all you need to do to run the app is to execute dotnet run from the project root directory.

Azure App Configuration and Blob Storage on Local

You need to setup the connection string. It varies slightly whether using Docker or not. Be sure to also update the appropriate appsettings.json too.

DOCKER

In the docker.development.secret.env file created earlier, add the following line:

ConnectionStrings__AzureAppConfiguration=<YOUR CONNECTION STRING HERE>
ConnectionStrings__<ServiceName from Blob Config Item>=<YOUR CONNECTION STRING HERE>

NON-DOCKER

Use the user secrets tool.

dotnet user-secrets set "ConnectionStrings:AzureAppConfiguration" "<YOUR CONNECTION STRING HERE>"
dotnet user-secrets set "ConnectionStrings:<ServiceName from Blob Config Item>" "<YOUR CONNECTION STRING HERE>"