This Terraform has some ACME cert resources from Let's Encrypt. When those need renewing, just reapplying the config should be enough.
Recommended to setup pre-commit script (runs terraform fmt --recursive on commit):
# see what you are about to setup to run on your computer every time you commit
cat setup-pre-commit.sh
# in root directory
./setup-pre-commit.sh
Initialize terraform by running:
az login
terraform init
terraform workspace select prod
Run terraform plan
to see changes. Run terraform fmt
before committing to avoid linter errors.
The ACME certificate challenge to Azure doesn't seem to work if running terraform apply
locally. Due to this and some clearer state of "what's actually deployed", it is preferred that you let the workflow run terraform apply
for you. The workflow runs apply
on main-branch for prod workspace, and plan
on PRs.
Sometimes you get yourself in a situation where Terraform tries to create an already-existing resource (see below for examples). You have two options:
- Delete the Azure resource(s) and re-run the deployment (if it's something lightweight and won't reappear too early).
- Import the Azure resource(s) to Terraform state (Recommended, instructions below).
To import Azure resources, run:
terraform import module.<foo>.<bar> /subscriptions/<subscription-id>/<path>
Typically the item address, starting module.
, and the resource path, starting /subscriptions
, are printed to
the console very close to the deployment error. You can get our subscription ID from az account show
as "id"
.
This will also prompt for all the relevant secrets, but you can often just provide something random and it'll import just fine (or at least fix itself on the next deploy). If some secret is used by the imported resource, you might need to provide the real value.
- At least when changing CNAME'd CDN endpoints, and possibly other CNAME'd resources, Azure can cause issues.
- Firstly, you need to remove the CNAME to delete the existing resource and then re-create the CNAME before re-creating the resource. This does not play well with the fact that you sometimes need to re-create CDN endpoints. If this starts causing repeated issues, we'll apply the workaround from the relevant azurerm backend issue, but otherwise we'll keep it as-is to avoid subdomain takeovers.
- As a bonus, disabling and re-enabling TLS on a CDN custom domain takes 8 hours, during which re-creation fails. The cloud is clearly the future :~)
- Azure is "user-friendly" and does stuff like creating a
$web
container when you enable static website serving on a storage account. However, this causes a collision if we also define said container in Terraform. This requires importing or deleting resources (see above). - With Azure, failed applies often result in the resources being created anyway, which again forces you to then manually fix collisions.
Create a new app for each different deployment.
Azure credentials need four pieces of information. Most of these can be found from Azure Portal → Azure Active Directory → App Registrations → (your app).
ARM_CLIENT_ID
: Application (client) ID in Azure Portal,"appId"
inaz ad sp show
.ARM_CLIENT_SECRET
: Client secret in Azure Portal (under Certificates and secrets).ARM_SUBSCRIPTION_ID
: Subscription ID in Azure Portal under Subscriptions,"id
" inaz account show
.ARM_TENANT_ID
: Directory (tenant) ID in Azure Portal,"appOwnerTenantId"
inaz ad sp show
.
Client secrets expire after (at most) 2 years. When that happens, just generate a new secret under Certificates and secrets in the portal.
When used as AZURE_CREDENTIALS
for az login
, use the format generated by az ad sp create-for-rbac --sdk-auth
:
{
"clientId": "ARM_CLIENT_ID from above",
"clientSecret": "ARM_CLIENT_SECRET from above",
"subscriptionId": "ARM_SUBSCRIPTION_ID from above",
"tenantId": "ARM_TENANT_ID from above"
}
(The JSON format is being deprecated by Azure, but I'm not sure what they're replacing it with. All documentation still
uses --sdk-auth
.)