Skip to content

Commit 957eb9a

Browse files
avalor1Andreas Hering
andauthored
Add Azure blob storage provider (#89)
* Trigger tests * Trigger more tests * Add azure block storage provider * Use FQCN * Adjust file permissions * Link to service principal creation docs * Remove prerequisite not needed when using azbs provider * Add azure.azcollection dependency * Fix missing loop/when part --------- Co-authored-by: Andreas Hering <andreas.hering@t-systems.com>
1 parent f854d03 commit 957eb9a

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

docs/http-challenge/azbs.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Variables for Azure blob storage http-challenge
2+
3+
| Variable | Required | Default | Description
4+
|-----------------------|----------|-----------|------------
5+
| acme_azbs_resource_group | yes | | Name of the Azure resource group to which the storage account has been allocated
6+
| acme_azbs_storage_account_name | yes | | Azure storage account name which should be used
7+
| acme_azbs_container_name | yes | | Azure container name which will be used/created in Azure storage account
8+
| acme_azbs_subscription_id | yes | | Azure subscription id
9+
| acme_azbs_client_id | yes | | Client ID of service principal/application
10+
| acme_azbs_secret | yes | | Value of secret of service principal/application (Note: not the ID)
11+
| acme_azbs_tenant_id | yes | | Tenant ID of service principal/application
12+
13+
## Validation
14+
15+
You have to create a service principal/application in the Azure Active Directory.
16+
This can be done via Frontend, Azure CLI or terraform.
17+
See https://learn.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals
18+
19+
You also have to set a redirect rule in your proxy or webserver to allow the acme challenge bot to read the file, during the http-01 challenge to work.
20+
21+
*Please note that the URL for the storage account and container needs to be adjusted to the name of your used account and container.*
22+
23+
**HaProxy:**
24+
*works with version >= 1.6*
25+
26+
```bash
27+
http-request redirect code 301 location https://your-storage-account-name.blob.core.windows.net[url,regsub(^/.well-known/acme-challenge,/my-containername,)] if { path_beg /.well-known/acme-challenge }
28+
```
29+
30+
(can be set in frontend or backend definition)
31+
32+
**Apache:**
33+
34+
```bash
35+
RewriteRule \.well-known/acme-challenge/(.*) https://your-storage-account-name.blob.core.windows.net/your-container-name/$1
36+
```
37+
38+
**Nginx:**
39+
40+
```bash
41+
rewrite \.well-known/acme-challenge/(.*) https://your-storage-account-name.blob.core.windows.net/your-container-name/$1
42+
```
43+
44+
## Usage
45+
46+
> you should think about encrypting all azure account infos
47+
48+
```yaml
49+
- name: create the certificate for example.com
50+
hosts: localhost
51+
collections:
52+
- t_systems_mms.acme
53+
roles:
54+
- acme
55+
vars:
56+
acme_domain:
57+
certificate_name: "example.com"
58+
zone: "example.com"
59+
email_address: "ssl-admin@example.com"
60+
subject_alt_name:
61+
- example.com
62+
- domain1.example.com
63+
- domain2.example.com
64+
acme_challenge_provider: "azbs"
65+
acme_use_live_directory: false
66+
acme_account_email: "ssl-admin@example.com"
67+
acme_azbs_resource_group: "my-resource-group"
68+
acme_azbs_storage_account_name: "my-storage-account-name"
69+
acme_azbs_container_name: "my-container"
70+
acme_azbs_subscription_id: "0000-11111-2222-3333-444444"
71+
acme_azbs_client_id: "1234-21231-14152-1231"
72+
acme_azbs_secret: !vault |
73+
$ANSIBLE_VAULT;1.1;AES256
74+
...
75+
acme_azbs_tenant_id: "2132184-3534543-54354-3543"
76+
```

galaxy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dependencies:
2323
community.crypto: '>=1.0.0'
2424
openstack.cloud: '>=1.2.1'
2525
amazon.aws: '>=5.0.0'
26+
azure.azcollection: '>=1.14.0'
2627
repository: 'https://github.com/T-Systems-MMS/ansible-collection-acme'
2728
documentation: 'https://github.com/T-Systems-MMS/ansible-collection-acme'
2829
homepage: 'https://github.com/T-Systems-MMS/ansible-collection-acme'
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
- name: Validate challenge only if it is created or changed # noqa no-handler
3+
when: challenge is changed
4+
block:
5+
- name: Create challenge file with SAN domain for azure blob storage upload # noqa template-instead-of-copy
6+
ansible.builtin.copy:
7+
dest: "acme-challenge.{{ item }}"
8+
content: "{{ challenge['challenge_data'][item]['http-01']['resource_value'] }}"
9+
mode: 0640
10+
loop: "{{ acme_domain.subject_alt_name }}"
11+
when:
12+
- acme_domain.subject_alt_name is defined
13+
# only runs if the challenge is run the first time, because then there is challenge_data
14+
- challenge['challenge_data'][item] is defined
15+
16+
- name: Create storage container and upload challenge file to it
17+
azure.azcollection.azure_rm_storageblob:
18+
resource_group: "{{ acme_azbs_resource_group }}"
19+
storage_account_name: "{{ acme_azbs_storage_account_name }}"
20+
public_access: "blob"
21+
container: "{{ acme_azbs_container_name }}"
22+
blob: "{{ challenge['challenge_data'][item]['http-01']['resource'] }}"
23+
src: "acme-challenge.{{ item }}"
24+
content_type: 'text/plain' # _type or _encoding have to be set
25+
subscription_id: "{{ acme_azbs_subscription_id }}"
26+
client_id: "{{ acme_azbs_client_id }}"
27+
secret: "{{ acme_azbs_secret }}"
28+
tenant: "{{ acme_azbs_tenant_id }}"
29+
loop: "{{ acme_domain.subject_alt_name }}"
30+
when:
31+
- acme_domain.subject_alt_name is defined
32+
# only runs if the challenge is run the first time, because then there is challenge_data
33+
- challenge['challenge_data'][item] is defined
34+
35+
# validate certficate
36+
- name: Let the challenge be validated and retrieve the cert and intermediate certificate
37+
community.crypto.acme_certificate:
38+
account_key_src: "{{ acme_account_key_path }}"
39+
account_email: "{{ acme_account_email }}"
40+
csr: "{{ acme_csr_path }}"
41+
cert: "{{ acme_cert_path }}"
42+
fullchain: "{{ acme_fullchain_path }}"
43+
chain: "{{ acme_intermediate_path }}"
44+
challenge: http-01
45+
force: "{{ acme_force_renewal | default(false) }}"
46+
acme_directory: "{{ acme_directory }}"
47+
acme_version: 2
48+
terms_agreed: true
49+
remaining_days: "{{ acme_remaining_days }}"
50+
data: "{{ challenge }}"
51+
52+
- name: Remove challenge file for SAN domain from azure blob storage container
53+
azure.azcollection.azure_rm_storageblob:
54+
resource_group: "{{ acme_azbs_resource_group }}"
55+
storage_account_name: "{{ acme_azbs_storage_account_name }}"
56+
container: "{{ acme_azbs_container_name }}"
57+
blob: "{{ challenge['challenge_data'][item]['http-01']['resource'] }}"
58+
state: absent
59+
subscription_id: "{{ acme_azbs_subscription_id }}"
60+
client_id: "{{ acme_azbs_client_id }}"
61+
secret: "{{ acme_azbs_secret }}"
62+
tenant: "{{ acme_azbs_tenant_id }}"
63+
loop: "{{ acme_domain.subject_alt_name }}"
64+
when:
65+
- acme_domain.subject_alt_name is defined
66+
# only runs if the challenge is run the first time, because then there is challenge_data
67+
- challenge['challenge_data'][item] is defined
68+
69+
- name: Remove challenge file for SAN domain from fs
70+
ansible.builtin.file:
71+
dest: "acme-challenge.{{ item }}"
72+
state: absent
73+
loop: "{{ acme_domain.subject_alt_name }}"
74+
when:
75+
- acme_domain.subject_alt_name is defined
76+
# only runs if the challenge is run the first time, because then there is challenge_data
77+
- challenge['challenge_data'][item] is defined

0 commit comments

Comments
 (0)