-
Notifications
You must be signed in to change notification settings - Fork 33
/
aci_oauth2.azcli
308 lines (287 loc) · 10.9 KB
/
aci_oauth2.azcli
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
###############################################
# Azure Container Instances with Azure CLI
#
# Deploys a container group with SSL offload,
# OAuth2 proxy and AKV integration
#
# Jose Moreno, October 2020
###############################################
# ToDo:
# - Redundancy with TM/AFD
# Variables
aci_name=sslaci
aci_dns=${aci_name}${RANDOM}
aci_fqdn=${aci_dns}.${location}.azurecontainer.io
# Certificates
openssl req -new -newkey rsa:2048 -nodes -keyout ssl.key -out ssl.csr -subj "/C=US/ST=WA/L=Redmond/O=AppDev/OU=IT/CN=${aci_dns}.${location}.azurecontainer.io"
openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
# Create nginx.conf for SSL
nginx_config_file=/tmp/nginx.conf
cat <<EOF > $nginx_config_file
user nginx;
worker_processes auto;
events {
worker_connections 1024;
}
pid /var/run/nginx.pid;
http {
server {
listen [::]:443 ssl;
listen 443 ssl;
server_name localhost;
ssl_protocols TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m; # a 1mb cache can hold about 4000 sessions, so we can hold 40000 sessions
ssl_session_timeout 24h;
keepalive_timeout 300; # up from 75 secs default
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
ssl_certificate /etc/nginx/ssl.crt;
ssl_certificate_key /etc/nginx/ssl.key;
location /api/ {
proxy_pass http://127.0.0.1:8080 ;
proxy_set_header Connection "";
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
location / {
proxy_pass http://127.0.0.1:4180 ;
proxy_set_header Connection "";
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
}
EOF
# Encode to Base64
nginx_conf=$(cat $nginx_config_file | base64)
ssl_crt=$(cat ssl.crt | base64)
ssl_key=$(cat ssl.key | base64)
# Create database
sql_server_name=sqlserver$RANDOM
sql_db_name=mydb
sql_username=azure
sql_password=Microsoft123!
az sql server create -n $sql_server_name -g $rg -l $location --admin-user $sql_username --admin-password $sql_password
sql_server_fqdn=$(az sql server show -n $sql_server_name -g $rg -o tsv --query fullyQualifiedDomainName)
az sql db create -n $sql_db_name -s $sql_server_name -g $rg -e Basic -c 5 --no-wait
# Create key vault
akv_name=akv$RANDOM
az keyvault create -n $akv_name -g $rg -l $location
az keyvault secret set -n sqlpassword --value $sql_password --vault-name $akv_name
# Create user identity
identity_name=myACIid
az identity create -n $identity_name -g $rg
identity_spid=$(az identity show -g $rg -n $identity_name --query principalId -o tsv)
identity_appid=$(az identity show -g $rg -n $identity_name --query clientId -o tsv)
identity_id=$(az identity show -g $rg -n $identity_name --query id -o tsv)
az keyvault set-policy -n $akv_name -g $rg --object-id $identity_spid --secret-permissions get
scope=$(az group show -n $rg --query id -o tsv)
az role assignment create --scope $scope --role Contributor --assignee $identity_appid
# Create script for init container
storage_account_name="$rg$RANDOM"
az storage account create -n $storage_account_name -g $rg --sku Standard_LRS --kind StorageV2
storage_account_key=$(az storage account keys list --account-name $storage_account_name -g $rg --query '[0].value' -o tsv)
az storage share create --account-name $storage_account_name --account-key $storage_account_key --name initscript
init_script_filename=init.sh
init_script_path=/tmp/
cat <<EOF > ${init_script_path}${init_script_filename}
echo "DEBUG: Environment variables:"
printenv
echo "Logging into Azure..."
az login --identity
echo "Getting secrets for Azure Key Vault \$AKV_NAME..."
az keyvault secret show --vault-name \$AKV_NAME -n sqlpassword --query 'value' -o tsv > /secrets/SQL_PASSWORD
echo "Getting my public IP addresss..."
myip=\$(curl -s4 ifconfig.co)
echo "Adding \$myip to firewall rules of SQL Server \$SQL_SERVER_NAME in RG \$RG..."
az sql server firewall-rule create -g \$RG -s \$SQL_SERVER_NAME -n \$RANDOM --start-ip-address \$myip --end-ip-address \$myip
EOF
az storage file upload --account-name $storage_account_name --account-key $storage_account_key -s initscript --source ${init_script_path}${init_script_filename}
# Create AAD app for authentication
aad_app_id=$(az ad app create --display-name "$aci_name" --identifier-uris "https://${aci_fqdn}" --query appId -o tsv)
ad_app_appid=$(az ad app show --id $aad_app_id --query appId -o tsv)
az ad app update --id $aad_app_id --reply-urls "https://${aci_fqdn}/oauth2/callback"
az ad sp create --id $aad_app_id
ad_app_secret=$(az ad sp credential reset --name $aad_app_id --credential-description "aci test" --query password -o tsv)
az ad app permission add \
--id $aad_app_id \
--api 00000003-0000-0000-c000-000000000000 \
--api-permissions e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope 37f7f235-527c-4136-accd-4a02d197296e=Scope
az ad app permission grant --id $aad_app_id --api 00000003-0000-0000-c000-000000000000
az ad app permission admin-consent --id $aad_app_id
# Create YAML
aci_yaml_file=/tmp/sqlapi.yaml
cat <<EOF > $aci_yaml_file
apiVersion: 2019-12-01
location: westus
name: $aci_name
identity:
type: UserAssigned
userAssignedIdentities:
$identity_id: {}
properties:
initContainers:
- name: azcli
properties:
image: microsoft/azure-cli:latest
command:
# - "az login --identity && az keyvault secret show --vault-name $akv_name -n sqlpassword --query 'value' -o tsv > /secrets/SQL_PASSWORD"
# - "touch"
# - "/secrets/helloworld.txt"
- "/bin/sh"
- "-c"
- "/mnt/init/$init_script_filename"
environmentVariables:
- name: RG
value: $rg
- name: AKV_NAME
value: $akv_name
- name: SQL_SERVER_NAME
value: $sql_server_name
volumeMounts:
- name: secrets
mountPath: /secrets
- name: initscript
mountPath: /mnt/init/
containers:
- name: nginx
properties:
image: nginx
ports:
- port: 443
protocol: TCP
resources:
requests:
cpu: 1.0
memoryInGB: 1
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx
- name: oauth
properties:
image: quay.io/oauth2-proxy/oauth2-proxy:latest
environmentVariables:
- name: OAUTH2_PROXY_EMAIL_DOMAINS
value: "*"
- name: OAUTH2_PROXY_REVERSE_PROXY
value: true
- name: OAUTH2_PROXY_COOKIE_SECRET
secureValue: ffdsfwerewrwe173
- name: OAUTH2_PROXY_UPSTREAMS
value: http://127.0.0.1:80/
- name: OAUTH2_PROXY_PASS_HOST_HEADER
value: false
- name: OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER
value: true
- name: OAUTH2_PROXY_PROVIDER
value: azure
- name: OAUTH2_PROXY_CLIENT_ID
value: $ad_app_appid
- name: OAUTH2_PROXY_CLIENT_SECRET
secureValue: $ad_app_secret
ports:
- port: 4180
protocol: TCP
resources:
requests:
cpu: 1.0
memoryInGB: 1
- name: web
properties:
image: erjosito/web:1.0
environmentVariables:
- name: API_URL
value: 127.0.0.1:8080
ports:
- port: 80
protocol: TCP
resources:
requests:
cpu: 0.5
memoryInGB: 0.5
- name: sqlapi
properties:
image: erjosito/sqlapi:1.0
environmentVariables:
- name: SQL_SERVER_USERNAME
value: $sql_username
- name: SQL_SERVER_PASSWORD
secureValue: $sql_password
- name: SQL_SERVER_FQDN
value: $sql_server_fqdn
- name: SQL_SERVER_DB
value: $sql_db_name
ports:
- port: 8080
protocol: TCP
resources:
requests:
cpu: 0.5
memoryInGB: 0.5
volumeMounts:
- name: secrets
mountPath: /secrets/
volumes:
- name: nginx-config
secret:
ssl.crt: "$ssl_crt"
ssl.key: "$ssl_key"
nginx.conf: "$nginx_conf"
- name: secrets
emptyDir: {}
- name: initscript
azureFile:
readOnly: false
shareName: initscript
storageAccountName: $storage_account_name
storageAccountKey: $storage_account_key
ipAddress:
ports:
- port: 443
protocol: TCP
type: Public
dnsNameLabel: $aci_dns
osType: Linux
tags: null
type: Microsoft.ContainerInstance/containerGroups
EOF
# Verify created YAML
# more $aci_yaml_file
# Deploy ACI
az container create -g $rg --file $aci_yaml_file
echo "Container FQDN: $aci_dns"
# Add public IP to SQL Server Firewall
aci_source_ip=40.91.206.16 # Take this from the GUI
az sql server firewall-rule create -g $rg -s $sql_server_name -n public_sqlapi_aci-source --start-ip-address $aci_source_ip --end-ip-address $aci_source_ip
# Show
az container list -g $rg -o table
az container show -n $aci_name -g $rg --query ipAddress
az container show -n $aci_name -g $rg --query instanceView.events -o table
# Logs
az container logs -n $aci_name -g $rg --container-name azcli
az container logs -n $aci_name -g $rg --container-name nginx
az container logs -n $aci_name -g $rg --container-name oauth
az container logs -n $aci_name -g $rg --container-name web
az container logs -n $aci_name -g $rg --container-name sqlapi
# Verify Azure SQL Server rules
az sql server firewall-rule list -s $sql_server_name -g $rg -o table
# Exec
az container exec -n $aci_name -g $rg --container-name oauth --exec-command /bin/sh
az container exec -n $aci_name -g $rg --container-name azcli --exec-command /bin/sh
az container exec -n $aci_name -g $rg --container-name sqlapi --exec-command /bin/sh
az container exec -n $aci_name -g $rg --container-name sqlapi --exec-command "ls -l /secrets/SQL_PASSWORD"
# Restart containers, for example after image update
az container restart -n $aci_name -g $rg
# Cleanup
az container delete -n $aci_name -g $rg -y
# Danger Zone!
# az group delete -n $rg -y --no-wait