-
Notifications
You must be signed in to change notification settings - Fork 1
414 lines (341 loc) · 18.7 KB
/
deploy-iac.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
# This workflow will deploy all the Azure services, including ACA, ACA Env., ACR, KV & secrets, MYSQL (eventually with a Firewall rule to allow your workstation IP)
# eventually if DEPLOY_TO_VNET is set to true : also VNet, ACA Env. deployed to VNet, private DNS-Zone, client VM deployed to the VNet
name: Deploy IaC with Azure Bicep
env:
APP_NAME: petcliaca
LOCATION: francecentral # westeurope
RG_KV: rg-iac-kv29 # RG where to deploy KV
RG_APP: rg-iac-aca-petclinic-mic-srv # RG where to deploy the other Azure services: ACA, ACA Env., MySQL, etc.
ACA_ENV_NAME: aca-env-pub # ACA Environment name. Ex 'aca-env-pub' or 'aca-env-corp' when deployed to your VNet
DEPLOY_TO_VNET: false
ACA_ENV_DNS_DUFFIX: acarocks.com
KV_NAME: kv-petcliaca29 # The name of the KV, must be UNIQUE. A vault name must be between 3-24 alphanumeric characters
SET_KV_ACCESS_POLICIES: false # let it to false
AZURE_CONTAINER_REGISTRY: acrpetcliaca # The name of the ACR, must be UNIQUE. The name must contain only alphanumeric characters, be globally unique, and between 5 and 50 characters in length.
REGISTRY_URL: acrpetcliaca.azurecr.io # set this to the URL of your registry
REPOSITORY: petclinic # set this to your ACR repository
VM_ADMIN_USER_NAME: adm_aca
MYSQL_SERVER_NAME: petcliaca
MYSQL_DB_NAME: petclinic
MYSQL_ADM_USR: mys_adm
MYSQL_TIME_ZONE: Europe/Paris
MYSQL_CHARACTER_SET: utf8
MYSQL_PORT: 3306
# ==== APPS ====
API_GATEWAY: api-gateway
ADMIN_SERVER: admin-server
CUSTOMERS_SERVICE: customers-service
VETS_SERVICE: vets-service
VISITS_SERVICE: visits-service
CONFIG_SERVER: config-server
DISCOVERY_SERVER: discovery-server
# GitHub Actions settings
GHA_SETTINGS_CFG_REGISTRY_URL: acrpetcliaca.azurecr.io
GHA_SETTINGS_CFG_REPO_URL: https://github.com/ezYakaEagle442/aca-java-petclinic-mic-srv
GHA_REVISION_NAME: aca-poc-101
# https://github.com/Azure/actions-workflow-samples/blob/master/assets/create-secrets-for-GitHub-workflows.md#consume-secrets-in-your-workflow
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-using-secrets
# ==== Secrets ====
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions
# Never use structured data as a secret
# Structured data can cause secret redaction within logs to fail, because redaction largely relies on finding an exact match for
# the specific secret value. For example, do not use a blob of JSON, XML, or YAML (or similar) to encapsulate a secret value,
# as this significantly reduces the probability the secrets will be properly redacted. Instead, create individual secrets for each sensitive value.
SPRING_DATASOURCE_PASSWORD: ${{ secrets.SPRING_DATASOURCE_PASSWORD }}
SPRING_CLOUD_AZURE_TENANT_ID: ${{ secrets.SPRING_CLOUD_AZURE_TENANT_ID }}
GHA_SETTINGS_CFG_CRD_CLIENT_ID: ${{ secrets.SPN_ID }}
GHA_SETTINGS_CFG_CRD_CLIENT_SECRET: ${{ secrets.SPN_PWD }}
VM_ADMIN_PASSWORD: ${{ secrets.VM_ADMIN_PASSWORD }}
# https://learn.microsoft.com/en-us/azure/key-vault/secrets/secrets-best-practices#secrets-rotation
# Because secrets are sensitive to leakage or exposure, it's important to rotate them often, at least every 60 days.
# Expiry date in seconds since 1970-01-01T00:00:00Z. Ex: 1672444800 ==> 31/12/2022'
SECRET_EXPIRY_DATE: 1703980800 # ==> 31/12/2023
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# ==== Versions ====
DEPLOYMENT_VERSION: 2.6.13
AZ_CLI_VERSION: 2.45.0
JAVA_VERSION: 11
on:
workflow_dispatch:
# required for https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
permissions:
id-token: write
contents: read
jobs:
deploy-kv:
runs-on: ubuntu-latest
steps:
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files
# /!\ IMPORTANT: The step that creates or updates the environment variable does not have access to the new value, but all subsequent steps in a job will have access.
- name: Set Base environment variables
run: |
echo "LOCAL_IP=$(curl whatismyip.akamai.com)" >> $GITHUB_ENV
shell: bash
- name: Login with GHA Runner SP
uses: azure/login@v1 # fails https://github.com/marketplace/actions/azure-login
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Checkout
uses: actions/checkout@v3 # https://github.com/actions/checkout
- name: Deploy Azure Key Vault
# uses: azure/CLI@v1.0.6 # https://github.com/marketplace/actions/azure-cli-action
# with:
#azcliversion: ${{ env.AZ_CLI_VERSION }}
# inlineScript: |
shell: bash
run: |
echo +++ START Step - Deploy Azure Key Vault
# leave this fake dummy accessPoliciesObject empty as anyway SET_KV_ACCESS_POLICIES is set to FALSE at this stage
# https://stackoverflow.com/questions/7316107/how-to-split-strings-over-multiple-lines-in-bash
apo=`cat <<-____HERE
{
"accessPolicies": [
{
"objectId":"fakeDummyAppIdentityId",
"tenantId":"fakeDummyTenantId",
"permissions": {
"secrets": [
"get",
"list"
]
}
}
]
}
____HERE`
echo **************************************************
# https://github.com/twpayne/chezmoi/discussions/1706
apo="{\"accessPolicies\":\"foo\"}"
accessPoliciesObject="${apo}"
echo accessPoliciesObject = "${accessPoliciesObject}"
echo **************************************************
pwd
ls -al
# /home/runner/work/aca-java-petclinic-mic-srv/aca-java-petclinic-mic-srv/.
az deployment group create --name aca-petclinic-kv -f iac/bicep/modules/kv/kv.bicep -g ${{ env.RG_KV }} \
-p appName=${{ env.APP_NAME }} \
-p kvName=${{ env.KV_NAME }} \
-p location=${{ env.LOCATION }}
# Allow GH Runner to access KV
# When Public access is disabled on KV, you need to add a network rule in the KV Firewall
- name: Authorize local IP to access the Azure Key Vault
run: |
az keyvault network-rule add --ip-address $LOCAL_IP --name ${{ env.KV_NAME }} --only-show-errors
sleep 10
shell: bash
- name: Create SPRING-DATASOURCE-PASSWORD secret in Azure Key Vault
run: |
az deployment group create --name aca-petclinic-kv-db-pwd -f iac/bicep/modules/kv/kv_sec_key.bicep -g ${{ env.RG_KV }} \
-p appName=${{ env.APP_NAME }} \
-p kvName=${{ env.KV_NAME }} \
-p secretName="SPRING-DATASOURCE-PASSWORD" \
-p secretValue=${{ secrets.SPRING_DATASOURCE_PASSWORD }} \
-p secretExpiryDate=${{ env.SECRET_EXPIRY_DATE }}
shell: bash
- name: Create SPRING-CLOUD-AZURE-TENANT-ID secret in Azure Key Vault
run: |
az deployment group create --name aca-petclinic-kv-tenant -f iac/bicep/modules/kv/kv_sec_key.bicep -g ${{ env.RG_KV }} \
-p appName=${{ env.APP_NAME }} \
-p kvName=${{ env.KV_NAME }} \
-p secretName="SPRING-CLOUD-AZURE-TENANT-ID" \
-p secretValue=${{ secrets.SPRING_CLOUD_AZURE_TENANT_ID }} \
-p secretExpiryDate=${{ env.SECRET_EXPIRY_DATE }}
shell: bash
- name: Create SPN-ID secret in Azure Key Vault
run: |
az deployment group create --name aca-petclinic-kv-spn-id -f iac/bicep/modules/kv/kv_sec_key.bicep -g ${{ env.RG_KV }} \
-p appName=${{ env.APP_NAME }} \
-p kvName=${{ env.KV_NAME }} \
-p secretName="SPN-ID" \
-p secretValue=${{ env.GHA_SETTINGS_CFG_CRD_CLIENT_ID }} \
-p secretExpiryDate=${{ env.SECRET_EXPIRY_DATE }}
shell: bash
- name: Create SPN-PWD secret in Azure Key Vault
run: |
az deployment group create --name aca-petclinic-kv-spn-pwd -f iac/bicep/modules/kv/kv_sec_key.bicep -g ${{ env.RG_KV }} \
-p appName=${{ env.APP_NAME }} \
-p kvName=${{ env.KV_NAME }} \
-p secretName="SPN-PWD" \
-p secretValue=${{ env.GHA_SETTINGS_CFG_CRD_CLIENT_SECRET }} \
-p secretExpiryDate=${{ env.SECRET_EXPIRY_DATE }}
shell: bash
- name: Create VM-ADMIN-PASSWORD secret in Azure Key Vault
if: ${{ env.DEPLOY_TO_VNET }}
run: |
az deployment group create --name aca-petclinic-kv-vm-pwd -f iac/bicep/modules/kv/kv_sec_key.bicep -g ${{ env.RG_KV }} \
-p appName=${{ env.APP_NAME }} \
-p kvName=${{ env.KV_NAME }} \
-p secretName="VM-ADMIN-PASSWORD" \
-p secretValue=${{ secrets.VM_ADMIN_PASSWORD }} \
-p secretExpiryDate=${{ env.SECRET_EXPIRY_DATE }}
shell: bash
- name: Disable local IP access to the Key Vault
if: ${{ always() }}
run: |
az keyvault network-rule remove --ip-address $LOCAL_IP --name ${{ env.KV_NAME }} --only-show-errors
shell: bash
deploy-iac:
runs-on: ubuntu-latest
needs: deploy-kv
# required for https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
permissions:
id-token: write
contents: read
steps:
- name: Set Base environment variables
run: |
echo "LOCAL_IP=$(curl whatismyip.akamai.com)" >> $GITHUB_ENV
shell: bash
- name: Login with GHA Runner SP
uses: azure/login@v1 # fails https://github.com/marketplace/actions/azure-login
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Checkout
uses: actions/checkout@v3 # https://github.com/actions/checkout
- name: Deploy the pre-req
run: |
# --debug # --what-if to test like a dry-run
echo ""
echo "About ACR Authentication options read https://learn.microsoft.com/en-us/azure/container-registry/container-registry-authentication?source=recommendations&tabs=azure-cli#authentication-options"
echo "ACR adminUserEnabled option : Single account per registry, not recommended for multiple users . This registry must have the Admin User enabled, or the integration with ACA will not work from the Azure portal."
echo ""
az deployment group create --name aca-petclinic-pre-req -f iac/bicep/pre-req.bicep -g ${{ env.RG_APP }} \
-p appName=${{ env.APP_NAME }} \
-p location=${{ env.LOCATION }} \
-p kvName=${{ env.KV_NAME }} \
-p kvRGName=${{ env.RG_KV }} \
-p acrName=${{ env.AZURE_CONTAINER_REGISTRY }} \
-p azureContainerAppEnvName=${{ env.ACA_ENV_NAME }} \
-p dnsSuffix=${{ env.ACA_ENV_DNS_DUFFIX }} \
-p deployToVNet=${{ env.DEPLOY_TO_VNET }}
az deployment group show \
-g ${{ env.RG_APP }} \
-n aca-petclinic-pre-req \
--query properties.outputs.appInsightsConnectionString.value
vetsServicePrincipalId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.vetsServicePrincipalId.value -o tsv)
vetsServiceClientId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.vetsServiceClientId.value -o tsv)
visitsServicePrincipalId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.visitsServicePrincipalId.value -o tsv)
visitsServiceClientId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.visitsServiceClientId.value -o tsv)
configServerPrincipalId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.configServerPrincipalId.value -o tsv)
configServerClientId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.configServerClientId.value -o tsv)
customersServicePrincipalId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.customersServicePrincipalId.value -o tsv)
customersServiceClientId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.customersServiceClientId.value -o tsv)
aksClusterPrincipalId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.aksIdentityPrincipalId.value -o tsv)
aksClusterClientId=$(az deployment group show --name aca-identities -g ${{ env.RG_APP }} --query properties.outputs.aksIdentityClientId.value -o tsv)
az deployment group create --name kv-role-assignments -f iac/bicep/modules/kv/kvRoleAssignments.bicep -g ${{ env.RG_KV }} \
-p kvName=${{ env.KV_NAME }} \
-p configServerIdentityId=$configServerPrincipalId \
-p vetsIdentityId=$vetsServicePrincipalId \
-p visitsIdentityId=$visitsServicePrincipalId \
-p customersIdentityId=$customersServicePrincipalId \
-p kvRoleType=KeyVaultSecretsUser
shell: bash
# TODO
# /!\ the ACA StaticIp is the ingress ip of the environment, NOT the outboundIP
# today the the outboundIP can be got ONLY from the Apps NOT yet from the Env., they all share the same the outboundIP
# KV must Allow azureContainerAppsOutboundPubIP in the IP rules ...
# MySQL DB Must allow azureContainerAppsOutboundPubIP to access in the IP rules ...
# workaround : deploy a hello world App and get MyApp.properties.outboundIpAddresses
# see https://github.com/microsoft/azure-container-apps/issues/469
- name: Whitelist ACA Env. OutboundIP
run: |
# az provider register --namespace Microsoft.App
az config set extension.use_dynamic_install=yes_without_prompt
envOutboundIP=$(az containerapp create \
--name hello-test \
--resource-group ${{ env.RG_APP }} \
--environment ${{ env.ACA_ENV_NAME }} \
--image mcr.microsoft.com/azuredocs/containerapps-helloworld:latest \
--target-port 80 \
--ingress 'external' \
--query properties | jq .outboundIpAddresses)
echo "hello-test ACA test created"
# az containerapp show --name hello-test -g ${{ env.RG_APP }} --query properties | jq .outboundIpAddresses
echo "About to Whitelist ACA Env. OutboundIP in KV & MySQL"
echo $envOutboundIP
az deployment group create --name aca-kv-mysql-set-ip-rules -f iac/bicep/set-ip-rules.bicep -g ${{ env.RG_APP }} \
-p appName=${{ env.APP_NAME }} \
-p location=${{ env.LOCATION }} \
-p kvName=${{ env.KV_NAME }} \
-p kvRGName=${{ env.RG_KV }} \
-p administratorLogin=${{ env.MYSQL_ADM_USR }} \
-p dbServerName=${{ env.MYSQL_SERVER_NAME }} \
-p vNetRules=[]
az containerapp delete --name hello-test -g ${{ env.RG_APP }} --yes
echo "hello-test ACA test deleted"
shell: bash
- name: Azure Logout security hardening
run: |
az logout
az cache purge
az account clear
shell: bash
# https://docs.github.com/en/actions/using-workflows/reusing-workflows#calling-a-reusable-workflow
# invalid value workflow reference: references to workflows must be prefixed with format 'owner/repository/' or './' for local workflows
call-maven-build-workflow:
name: Trigger Maven for backend services
needs: deploy-iac
uses: ./.github/workflows/maven-build.yml # .github/workflows/maven-build.yml@main ==> references to workflows must be prefixed with format 'owner/repository/' or './' for local workflows
secrets: inherit # pass all secrets
# envPAT: ${{ secrets.envPAT }} # pass just this secret
permissions:
id-token: write
contents: read
packages: write
call-maven-build-ui-workflow:
name: Trigger Maven for the UI
needs: deploy-iac
uses: ./.github/workflows/maven-build-ui.yml
secrets: inherit
permissions:
id-token: write
contents: read
packages: write
call-deploy-cfg-srv-workflow:
name: Trigger Deployment for the Config-Server
needs: [deploy-iac, call-maven-build-workflow]
uses: ./.github/workflows/deploy-app-cfg-srv.yml
with:
tag_id: ${{ needs.call-maven-build-workflow.outputs.tag_id }}
secrets: inherit
# required for https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
permissions:
id-token: write
contents: read
call-deploy-apps-svc-workflow:
name: Trigger App Deployment for the Backend services
needs: [deploy-iac, call-maven-build-workflow, call-deploy-cfg-srv-workflow]
uses: ./.github/workflows/deploy-app-svc.yml
with:
tag_id: ${{ needs.call-maven-build-workflow.outputs.tag_id }}
secrets: inherit
# required for https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
permissions:
id-token: write
contents: read
call-deploy-ui-workflow:
name: Trigger UI Deployment
needs: [deploy-iac, call-maven-build-ui-workflow, call-deploy-apps-svc-workflow]
uses: ./.github/workflows/deploy-app-ui.yml
with:
tag_id: ${{ needs.call-maven-build-ui-workflow.outputs.tag_id }}
secrets: inherit
# required for https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
permissions:
id-token: write
contents: read
call-db-init-workflow:
name: Load Data to DB
needs: [deploy-iac, call-deploy-apps-svc-workflow, call-deploy-ui-workflow]
uses: ./.github/workflows/sql-load.yml
secrets: inherit
# required for https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure?tabs=azure-cli%2Clinux#set-up-azure-login-with-openid-connect-authentication
permissions:
id-token: write
contents: read