Add rover ignite initial templates
This commit is contained in:
Родитель
06f56f0d1c
Коммит
4bfa1ed587
|
@ -0,0 +1,15 @@
|
|||
# Cloud Adoption Framework landing zones for Terraform - Starter template for Azure Subscription Vending Machine (ASVM)
|
||||
|
||||
|
||||
```bash
|
||||
cd /tf/caf/templates/platform
|
||||
|
||||
rover ignite \
|
||||
--playbook /tf/caf/starter/templates/asvm/ansible.yaml \
|
||||
-e base_templates_folder=/tf/caf/starter/templates/landingzones \
|
||||
-e resource_template_folder=/tf/caf/starter/templates/resources \
|
||||
-e config_folder=/tf/caf/orgs/contoso/asvm \
|
||||
-e platform_config_folder=/tf/caf/orgs/contoso/platform \
|
||||
-e scenario=contoso
|
||||
|
||||
```
|
Двоичные данные
templates/landingzones/action_plugins/__pycache__/merge_vars.cpython-39.pyc
Normal file
Двоичные данные
templates/landingzones/action_plugins/__pycache__/merge_vars.cpython-39.pyc
Normal file
Двоичный файл не отображается.
|
@ -0,0 +1,155 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
An Ansible action plugin to allow explicit merging of dict and list facts.
|
||||
|
||||
https://github.com/leapfrogonline/ansible-merge-vars/blob/master/LICENSE.md
|
||||
|
||||
"""
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.utils.vars import isidentifier
|
||||
|
||||
|
||||
# Funky import dance for Ansible backwards compatitility (not sure if we
|
||||
# actually need to do this or not)
|
||||
try:
|
||||
from __main__ import display
|
||||
except ImportError:
|
||||
from ansible.utils.display import Display # pylint: disable=ungrouped-imports
|
||||
display = Display()
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
"""
|
||||
Merge all variables in context with a certain suffix (lists or dicts only)
|
||||
and create a new variable that contains the result of this merge. These
|
||||
initial suffixed variables can be definied anywhere in the inventory, or by
|
||||
any other means; as long as they're in the context for the running play,
|
||||
they'll be merged.
|
||||
|
||||
"""
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
suffix_to_merge = self._task.args.get('suffix_to_merge', '')
|
||||
merged_var_name = self._task.args.get('merged_var_name', '')
|
||||
dedup = self._task.args.get('dedup', True)
|
||||
expected_type = self._task.args.get('expected_type')
|
||||
recursive_dict_merge = bool(self._task.args.get('recursive_dict_merge', False))
|
||||
|
||||
if 'cacheable' in self._task.args.keys():
|
||||
display.deprecated(
|
||||
"The `cacheable` option does not actually do anything, since Ansible 2.5. "
|
||||
"No matter what, the variable set by this plugin will be set in the fact "
|
||||
"cache if you have fact caching enabled. To get rid of this warning, "
|
||||
"remove the `cacheable` argument from your merge_vars task. This warning "
|
||||
"will be removed in a future version of this plugin."
|
||||
)
|
||||
|
||||
# Validate args
|
||||
if expected_type not in ['dict', 'list']:
|
||||
raise AnsibleError("expected_type must be set ('dict' or 'list').")
|
||||
if not merged_var_name:
|
||||
raise AnsibleError("merged_var_name must be set")
|
||||
if not isidentifier(merged_var_name):
|
||||
raise AnsibleError("merged_var_name '%s' is not a valid identifier" % merged_var_name)
|
||||
if not suffix_to_merge.endswith('__to_merge'):
|
||||
raise AnsibleError("Merge suffix must end with '__to_merge', sorry!")
|
||||
|
||||
keys = sorted([key for key in task_vars.keys()
|
||||
if key.endswith(suffix_to_merge)])
|
||||
|
||||
display.v("Merging vars in this order: {}".format(keys))
|
||||
|
||||
# We need to render any jinja in the merged var now, because once it
|
||||
# leaves this plugin, ansible will cleanse it by turning any jinja tags
|
||||
# into comments.
|
||||
# And we need it done before merging the variables,
|
||||
# in case any structured data is specified with templates.
|
||||
merge_vals = [self._templar.template(task_vars[key]) for key in keys]
|
||||
|
||||
# Dispatch based on type that we're merging
|
||||
if merge_vals == []:
|
||||
if expected_type == 'list':
|
||||
merged = []
|
||||
else:
|
||||
merged = {}
|
||||
elif isinstance(merge_vals[0], list):
|
||||
merged = merge_list(merge_vals, dedup)
|
||||
elif isinstance(merge_vals[0], dict):
|
||||
merged = merge_dict(merge_vals, dedup, recursive_dict_merge)
|
||||
else:
|
||||
raise AnsibleError(
|
||||
"Don't know how to merge variables of type: {}".format(type(merge_vals[0]))
|
||||
)
|
||||
|
||||
return {
|
||||
'ansible_facts': {merged_var_name: merged},
|
||||
'changed': False,
|
||||
}
|
||||
|
||||
|
||||
def merge_dict(merge_vals, dedup, recursive_dict_merge):
|
||||
"""
|
||||
To merge dicts, just update one with the values of the next, etc.
|
||||
"""
|
||||
check_type(merge_vals, dict)
|
||||
merged = {}
|
||||
for val in merge_vals:
|
||||
if not recursive_dict_merge:
|
||||
merged.update(val)
|
||||
else:
|
||||
# Recursive merging of dictionaries with overlapping keys:
|
||||
# LISTS: merge with merge_list
|
||||
# DICTS: recursively merge with merge_dict
|
||||
# any other types: replace (same as usual behaviour)
|
||||
for key in val.keys():
|
||||
if not key in merged:
|
||||
# first hit of the value - just assign
|
||||
merged[key] = val[key]
|
||||
elif isinstance(merged[key], list):
|
||||
merged[key] = merge_list([merged[key], val[key]], dedup)
|
||||
elif isinstance(merged[key], dict):
|
||||
merged[key] = merge_dict([merged[key], val[key]], dedup, recursive_dict_merge)
|
||||
else:
|
||||
merged[key] = val[key]
|
||||
return merged
|
||||
|
||||
|
||||
def merge_list(merge_vals, dedup):
|
||||
""" To merge lists, just concat them. Dedup if wanted. """
|
||||
check_type(merge_vals, list)
|
||||
merged = flatten(merge_vals)
|
||||
if dedup:
|
||||
merged = deduplicate(merged)
|
||||
return merged
|
||||
|
||||
|
||||
def check_type(mylist, _type):
|
||||
""" Ensure that all members of mylist are of type _type. """
|
||||
if not all(isinstance(item, _type) for item in mylist):
|
||||
raise AnsibleError("All values to merge must be of the same type, either dict or list")
|
||||
|
||||
|
||||
def flatten(list_of_lists):
|
||||
"""
|
||||
Flattens a list of lists:
|
||||
>>> flatten([[1, 2] [3, 4]])
|
||||
[1, 2, 3, 4]
|
||||
|
||||
I wish Python had this in the standard lib :(
|
||||
"""
|
||||
return list((x for y in list_of_lists for x in y))
|
||||
|
||||
|
||||
def deduplicate(mylist):
|
||||
"""
|
||||
Just brute force it. This lets us keep order, and lets us dedup unhashable
|
||||
things, like dicts. Hopefully you won't run into such big lists that
|
||||
this will ever be a performance issue.
|
||||
"""
|
||||
deduped = []
|
||||
for item in mylist:
|
||||
if item not in deduped:
|
||||
deduped.append(item)
|
||||
return deduped
|
|
@ -0,0 +1,80 @@
|
|||
# Get Platform subscriptions
|
||||
|
||||
- name: "Get platform subscriptions tfstate details"
|
||||
register: subscription_tfstate_file_name
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='{{ config.tfstates["platform"].platform_subscriptions.level | default('level1') }}' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name}[0]" -o json | jq -r .name
|
||||
|
||||
- debug:
|
||||
msg: "{{ subscription_tfstate_file_name.stdout }}"
|
||||
|
||||
- name: "Download platform subscriptions tfstate details"
|
||||
register: platform_subscription_tfstate_exists
|
||||
shell: |
|
||||
az storage blob download \
|
||||
--name "{{ config.tfstates["platform"].platform_subscriptions.tfstate | default('platform_subscriptions.tfstate') }}" \
|
||||
--account-name "{{ subscription_tfstate_file_name.stdout }}" \
|
||||
--container-name "tfstate" \
|
||||
--auth-mode "login" \
|
||||
--file "{{ job_cache_base_path }}/{{ config.tfstates["platform"].platform_subscriptions.tfstate | default('platform_subscriptions.tfstate') }}"
|
||||
|
||||
- name: "Get platform_subscriptions details"
|
||||
when: platform_subscription_tfstate_exists.rc == 0
|
||||
shell: "cat {{ job_cache_base_path }}/{{ config.tfstates[\"platform\"].platform_subscriptions.tfstate | default('platform_subscriptions.tfstate') }}"
|
||||
register: platform_subscriptions
|
||||
|
||||
- name: "Get platform_subscriptions json data"
|
||||
when: platform_subscription_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
platform_sub_jsondata: "{{ platform_subscriptions.stdout | from_json }}"
|
||||
|
||||
- name: "Get subscriptions list"
|
||||
when: platform_subscription_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
platform_subscriptions_details: "{{ platform_sub_jsondata | json_query(path) }}"
|
||||
vars:
|
||||
path: 'outputs.objects.value.{{ config.tfstates["platform"].platform_subscriptions.lz_key_name }}.subscriptions'
|
||||
|
||||
|
||||
# Get Platform keyvaults
|
||||
- name: "Get tfstate keyvaults account name"
|
||||
register: launchpad_storage_account
|
||||
ignore_errors: yes
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='{{ config.tfstates["platform"].launchpad.level | default('level0') }}' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name}[0]" -o json | jq -r .name
|
||||
|
||||
- debug:
|
||||
msg: "{{launchpad_storage_account}}"
|
||||
|
||||
- name: "Get tfstate keyvaults details"
|
||||
register: credentials_tfstate_exists
|
||||
when: launchpad_storage_account.stderr == ""
|
||||
ignore_errors: yes
|
||||
shell: |
|
||||
az storage blob download \
|
||||
--name "{{ config.tfstates["platform"].launchpad_credentials.tfstate | default('launchpad_credentials.tfstate') }}" \
|
||||
--account-name "{{ launchpad_storage_account.stdout }}" \
|
||||
--container-name "{{ config.tfstates["platform"].launchpad.workspace | default('tfstate') }}" \
|
||||
--auth-mode "login" \
|
||||
--file "~/.terraform.cache/launchpad/{{ config.tfstates["platform"].launchpad_credentials.tfstate | default('launchpad_credentials.tfstate') }}"
|
||||
|
||||
- name: "Get launchpad_credentials details"
|
||||
when: credentials_tfstate_exists is not skipped
|
||||
shell: "cat ~/.terraform.cache/launchpad/{{ config.tfstates[\"platform\"].launchpad_credentials.tfstate | default('launchpad_credentials.tfstate') }}"
|
||||
register: launchpad_credentials
|
||||
|
||||
- name: "Get launchpad_credentials json data"
|
||||
when: credentials_tfstate_exists is not skipped
|
||||
set_fact:
|
||||
credjsondata: "{{ launchpad_credentials.stdout | from_json }}"
|
||||
|
||||
- name: "Set keyvaults variable"
|
||||
when: credentials_tfstate_exists is not skipped
|
||||
set_fact:
|
||||
keyvaults: "{{ credjsondata | json_query(path) }}"
|
||||
vars:
|
||||
path: 'outputs.objects.value.launchpad_credentials_rotation.keyvaults'
|
|
@ -0,0 +1,84 @@
|
|||
- name: CAF Terraform - Generate configuration files
|
||||
hosts: localhost
|
||||
vars:
|
||||
base_templates_folder: "{{ base_templates_folder }}/asvm"
|
||||
resource_template_folder: "{{ base_templates_folder }}/resources"
|
||||
level: level3
|
||||
|
||||
|
||||
tasks:
|
||||
|
||||
- name: "Load variable for landingzones config"
|
||||
include_vars:
|
||||
name: asvm_config__to_merge
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "config.asvm.yaml|tfstates.asvm.yaml|deployments.yaml"
|
||||
|
||||
- name: "Set base variables"
|
||||
set_fact:
|
||||
job_cache_base_path: "/home/vscode/.terraform.cache"
|
||||
config: "{{asvm_config__to_merge}}"
|
||||
|
||||
- name: "Content of asvm_config__to_merge"
|
||||
debug:
|
||||
msg: "{{asvm_config__to_merge}}"
|
||||
|
||||
- name: "Load variable for platform config"
|
||||
include_vars:
|
||||
name: platform_config__to_merge
|
||||
dir: "{{config_folder_platform | default(config_folder)}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "caf.platform.yaml|tfstates.caf.yaml|tfstates.yaml"
|
||||
|
||||
- name: "Content of platform_config__to_merge"
|
||||
debug:
|
||||
msg: "{{platform_config__to_merge}}"
|
||||
|
||||
- name: Merge asvm and platform variables
|
||||
merge_vars:
|
||||
suffix_to_merge: config__to_merge
|
||||
merged_var_name: config
|
||||
expected_type: 'dict'
|
||||
recursive_dict_merge: True
|
||||
|
||||
- name: "Set base config variables"
|
||||
set_fact:
|
||||
config: "{{ ansible_facts.config }}"
|
||||
|
||||
- name: "Content of config"
|
||||
debug:
|
||||
msg: "{{config}}"
|
||||
|
||||
|
||||
- name: "Creates cache directory"
|
||||
file:
|
||||
path: "{{ job_cache_base_path }}/launchpad"
|
||||
state: directory
|
||||
|
||||
|
||||
- name: "{{ level }} | Get platform details (requires '-e config_folder_platform=path to yamls' path to be set)"
|
||||
include_tasks: "ansible-get-platform-details.yaml"
|
||||
when: config_folder_platform is defined
|
||||
|
||||
#
|
||||
# Level 3
|
||||
#
|
||||
|
||||
# landingzones deployments
|
||||
|
||||
- name: "{{ level }} | landingzones"
|
||||
include_tasks: "{{ level }}/ansible.yaml"
|
||||
loop: "{{asvm_config__to_merge.deployments.keys()}}"
|
||||
loop_control:
|
||||
loop_var: asvm_long_folder
|
||||
|
||||
#
|
||||
# Linters
|
||||
#
|
||||
|
||||
- name: Terraform linter
|
||||
shell: |
|
||||
terraform fmt -recursive {{ destination_base_path }}
|
|
@ -0,0 +1,66 @@
|
|||
- name: "Load variable for subscriptions"
|
||||
include_vars:
|
||||
name: subscriptions
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "subscriptions.asvm.yaml|subscription.asvm.yaml"
|
||||
|
||||
- name: "Content of subscriptions"
|
||||
debug:
|
||||
msg: "{{subscriptions}}"
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] Get tfstate details"
|
||||
register: subscription_tfstate_storage_account_name
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='{{ config.tfstates['asvm'][subscription_key].level }}' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name}[0]" -o json | jq -r .name
|
||||
|
||||
- debug:
|
||||
msg: "{{ subscription_tfstate_storage_account_name.stdout }}"
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] Download tfstate details"
|
||||
register: subscription_tfstate_exists
|
||||
ignore_errors: true
|
||||
shell: |
|
||||
az storage blob download \
|
||||
--name "{{ config.tfstates['asvm'][subscription_key].subscriptions.tfstate }}" \
|
||||
--account-name "{{ subscription_tfstate_storage_account_name.stdout }}" \
|
||||
--container-name "{{ config.tfstates['asvm'][subscription_key].workspace }}" \
|
||||
--auth-mode "login" \
|
||||
--file "{{ job_cache_base_path }}/{{ config.tfstates['asvm'][subscription_key].subscriptions.tfstate }}"
|
||||
|
||||
- debug:
|
||||
msg: "{{ subscription_tfstate_exists }}"
|
||||
when: subscriptions.subscriptions[subscription_key] is defined
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] Get landingzones_subscriptions details"
|
||||
shell: "cat {{ job_cache_base_path }}/{{ config.tfstates['asvm'][subscription_key].subscriptions.tfstate }}"
|
||||
register: platform_subscriptions
|
||||
when:
|
||||
- subscriptions.subscriptions[subscription_key] is defined
|
||||
- subscription_tfstate_exists.rc == 0
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] Get subscriptions data"
|
||||
when:
|
||||
- subscriptions.subscriptions[subscription_key] is defined
|
||||
- subscription_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
asvm_subscriptions_details: "{{ platform_subscriptions.stdout | from_json | json_query(path) }}"
|
||||
vars:
|
||||
path: 'outputs.objects.value."{{ config.tfstates["asvm"][subscription_key].subscriptions.lz_key_name }}".subscriptions'
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] cleanup"
|
||||
when:
|
||||
- subscriptions.subscriptions[subscription_key] is defined
|
||||
- subscription_tfstate_exists.rc == 0
|
||||
file:
|
||||
path: "{{ job_cache_base_path }}/{{ config.tfstates['asvm'][subscription_key].subscriptions.tfstate }}"
|
||||
state: absent
|
||||
|
||||
- debug:
|
||||
msg: "Platform subscriptions - {{ asvm_subscriptions_details }}"
|
||||
when:
|
||||
- subscriptions.subscriptions[subscription_key] is defined
|
||||
- subscription_tfstate_exists.rc == 0
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
- name: set destination paths
|
||||
set_fact:
|
||||
destination_path: "{{ destination_base_path }}/{{ subscription_key }}/subscription"
|
||||
deployment: "subscriptions"
|
||||
|
||||
- name: "Clean-up directory - subscription - {{ destination_path }}"
|
||||
file:
|
||||
path: "{{ destination_path }}"
|
||||
state: absent
|
||||
|
||||
- name: "Content of subscriptions' resources"
|
||||
debug:
|
||||
msg: "{{resources}}"
|
||||
|
||||
- name: "[{{ level }} {{ subscription_key }}] Creates directory"
|
||||
file:
|
||||
path: "{{ destination_path }}"
|
||||
state: directory
|
||||
|
||||
#
|
||||
# global_settings
|
||||
#
|
||||
- name: "[{{ level }} {{ subscription_key }}] - subscription - global_settings"
|
||||
when: resources.subscriptions[subscription_key].global_settings is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/global_settings.tfvars.j2"
|
||||
#
|
||||
# landingzone
|
||||
#
|
||||
- name: "[{{ level }} {{ subscription_key }}] - subscription - landingzone"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/landingzone.tfvars.j2"
|
||||
#
|
||||
# subscription
|
||||
#
|
||||
- name: "[{{ level }} {{ subscription_key }}] - subscription - subscription"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/subscriptions.tfvars.j2"
|
||||
|
||||
#
|
||||
# Readme
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - subscription - *.md"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ base_templates_folder }}/{{ level }}/subscription/*.md"
|
|
@ -0,0 +1,58 @@
|
|||
- name: set asvm context
|
||||
set_fact:
|
||||
asvm_folder: "{{ asvm_long_folder if 'path' not in asvm_long_folder else asvm_long_folder.path | regex_search('[^\/]+(?=\/$|$)') }}"
|
||||
|
||||
- name: "[{{ level }}-{{ asvm_folder }}] Set cache folder"
|
||||
set_fact:
|
||||
# job_cache_base_path: "/home/vscode/.terraform.cache"
|
||||
subscription_key: "{{ asvm_folder }}"
|
||||
|
||||
- name: "Load variable for deployments"
|
||||
include_vars:
|
||||
name: deployments
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "deployments.asvm.yaml|deployments.yaml"
|
||||
|
||||
- debug:
|
||||
msg: "{{deployments}}"
|
||||
|
||||
### Generate remote state storage containers
|
||||
|
||||
- name: "[{{ level }} {{ subscription_key }}] - remote state container"
|
||||
include_tasks: "{{ level }}/storage_containers/ansible.yaml"
|
||||
when:
|
||||
- deployments.deployments[subscription_key].storage_containers is defined
|
||||
|
||||
#### Get subscription_id
|
||||
|
||||
- name: "[{{ level }} {{ subscription_key }}] - subscription"
|
||||
include_tasks: "{{ level }}/ansible-subscription-id.yaml"
|
||||
when:
|
||||
- config.tfstates['asvm'][subscription_key].subscriptions is defined
|
||||
- config.tfstates['asvm'][subscription_key].subscriptions.subscription_id is not defined
|
||||
|
||||
### Subscription
|
||||
|
||||
- name: "Load variable for subscriptions"
|
||||
include_vars:
|
||||
name: resources
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "subscriptions.asvm.yaml|subscription.asvm.yaml|tfstates.asvm.yaml"
|
||||
|
||||
- name: "[{{ level }} {{ subscription_key }}] - subscription"
|
||||
include_tasks: "{{ level }}/ansible-subscription.yaml"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key] is defined
|
||||
- config.tfstates['asvm'][subscription_key].subscriptions.subscription_id is not defined
|
||||
|
||||
|
||||
#### Privileged resources to deploy in the landingzone
|
||||
|
||||
- name: "[{{ level }} {{ subscription_key }}] - resources"
|
||||
include_tasks: "{{ level }}/resources/ansible.yaml"
|
||||
when:
|
||||
- config.tfstates['asvm'][subscription_key].resources is defined
|
|
@ -0,0 +1,262 @@
|
|||
|
||||
- name: set destination paths
|
||||
set_fact:
|
||||
destination_path: "{{ destination_base_path }}/{{ subscription_key }}/resources"
|
||||
deployment: "resources"
|
||||
|
||||
- name: "Clean-up directory - subscription - {{ destination_path }}"
|
||||
file:
|
||||
path: "{{ destination_path }}"
|
||||
state: absent
|
||||
when: config.configuration_folders.asvm.cleanup_destination | default(true) | bool
|
||||
|
||||
- name: "Load variable for resources"
|
||||
include_vars:
|
||||
name: resources
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "resources.asvm.yaml"
|
||||
|
||||
- name: "Content of resources"
|
||||
debug:
|
||||
msg: "{{resources}}"
|
||||
|
||||
- name: "[{{ level }} {{ asvm_folder }}] - resources - Creates directory"
|
||||
file:
|
||||
path: "{{ destination_path }}"
|
||||
state: directory
|
||||
#
|
||||
# azuread_credentials
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - azuread_credentials"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_credentials is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_credentials.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_applications
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - azuread_applications"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_applications is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_applications.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_credential_policies
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - azuread_credential_policies"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_credential_policies is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_credential_policies.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_groups
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - azuread_groups"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_groups is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_groups.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_groups_membership
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - azuread_groups_membership"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_groups_membership is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_groups_membership.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_service_principals
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - azuread_service_principals"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_service_principals is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_service_principals.tfvars.j2"
|
||||
|
||||
#
|
||||
# custom_role_definitions
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - custom_role_definitions"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].custom_role_definitions is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/custom_role_definitions.tfvars.j2"
|
||||
|
||||
#
|
||||
# keyvaults
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - keyvaults"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].keyvaults is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/keyvaults.tfvars.j2"
|
||||
|
||||
#
|
||||
# keyvault_access_policies
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - keyvault_access_policies"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].keyvault_access_policies is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/keyvault_access_policies.tfvars.j2"
|
||||
|
||||
#
|
||||
# landingzone
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - landingzone"
|
||||
when:
|
||||
- deployments.deployments[subscription_key][deployment].landingzone is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/landingzone.tfvars.j2"
|
||||
|
||||
#
|
||||
# managed_identities
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - managed_identities"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].managed_identities is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/managed_identities.tfvars.j2"
|
||||
|
||||
#
|
||||
# network_security_group_definition
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - network_security_group_definition"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].network_security_group_definition is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/network_security_group_definition.tfvars.j2"
|
||||
|
||||
#
|
||||
# recovery_vaults
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - recovery_vaults"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].recovery_vaults is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/recovery_vaults.tfvars.j2"
|
||||
|
||||
#
|
||||
# resource_groups
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - resource_groups"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].resource_groups is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/resource_groups.tfvars.j2"
|
||||
|
||||
#
|
||||
# role_mapping
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - role_mapping"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].role_mapping is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/role_mapping.tfvars.j2"
|
||||
|
||||
#
|
||||
# virtual_hub_connections
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - virtual_hub_connections"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].virtual_hub_connections is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/virtual_hub_connections.tfvars.j2"
|
||||
|
||||
|
||||
#
|
||||
# virtual_networks
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - virtual_networks"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].virtual_networks is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/virtual_networks.tfvars.j2"
|
||||
|
||||
|
||||
#
|
||||
# Readme
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - resources - *.md"
|
||||
when: subscription_tfstate_exists.rc == 0
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ base_templates_folder }}/{{ level }}/resources/*.md"
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
### Deploy base resources in {{ asvm_folder }}
|
||||
|
||||
```bash
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
unset ARM_SKIP_PROVIDER_REGISTRATION
|
||||
|
||||
cd /tf/caf/landingzones
|
||||
git pull
|
||||
git checkout {{ resources.gitops.landingzones }}
|
||||
|
||||
rover \
|
||||
{% if config.platform_identity.azuread_identity_mode != "logged_in_user" %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_subscription_creation_landingzones.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ destination_path }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ asvm_subscriptions_details[asvm_folder].subscription_id }} \
|
||||
-tfstate {{ config.tfstates['asvm'][asvm_folder].resources.tfstate }} \
|
||||
--workspace {{ config.tfstates['asvm'][asvm_folder].workspace }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates['asvm'][asvm_folder].resources.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
rover logout
|
||||
|
||||
```
|
|
@ -0,0 +1,80 @@
|
|||
- name: set destination paths
|
||||
set_fact:
|
||||
destination_path: "{{ destination_base_path }}/storage_containers"
|
||||
deployment: "storage_containers"
|
||||
|
||||
- name: "Load variable for resources"
|
||||
include_vars:
|
||||
name: resources
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "tfstates.asvm.yaml|subscriptions.asvm.yaml|subscription.asvm.yaml"
|
||||
|
||||
- name: "Content of resources"
|
||||
debug:
|
||||
msg: "{{resources}}"
|
||||
|
||||
- name: "[{{ level }} {{ asvm_folder }}] - storage_containers - Creates directory"
|
||||
file:
|
||||
path: "{{ destination_path }}"
|
||||
state: directory
|
||||
|
||||
#
|
||||
# Get storage account names
|
||||
#
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - storage_containers - launchpad level3"
|
||||
register: storage_account_level3
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='level3' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name, resource_group:resourceGroup}[0]" -o json | jq -r
|
||||
|
||||
- debug:
|
||||
msg: "{{storage_account_level3.stdout}}"
|
||||
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - storage_containers - launchpad level4"
|
||||
register: storage_account_level4
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='level4' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name, resource_group:resourceGroup}[0]" -o json | jq -r
|
||||
|
||||
- debug:
|
||||
msg: "{{storage_account_level4.stdout}}"
|
||||
|
||||
|
||||
#
|
||||
# landingzone
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - storage_containers - landingzone"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/landingzone.tfvars.j2"
|
||||
|
||||
#
|
||||
# storage_containers
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - storage_containers - storage_containers"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ base_templates_folder }}/{{ level }}/storage_containers/storage_containers.tfvars.j2"
|
||||
|
||||
|
||||
#
|
||||
# Readme
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - storage_containers - *.md"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ base_templates_folder }}/{{ level }}/storage_containers/*.md"
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
### Create storage containers for the landingzone
|
||||
|
||||
```bash
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
cd /tf/caf/landingzones
|
||||
git pull
|
||||
git checkout {{ resources.gitops.landingzones }}
|
||||
|
||||
rover \
|
||||
{% if config.platform_identity.azuread_identity_mode != "logged_in_user" %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_subscription_creation_landingzones.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ destination_path }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.asvm[asvm_folder].subscriptions.tfstate }} \
|
||||
--workspace {{ config.tfstates.asvm[asvm_folder].subscriptions.workspace | default('tfstate') }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.asvm[asvm_folder].subscriptions.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
rover logout
|
||||
|
||||
```
|
|
@ -0,0 +1,16 @@
|
|||
storage_containers = {
|
||||
{% for key in resources.subscriptions.keys() %}
|
||||
{{ key }}_level3 = {
|
||||
name = "{{ resources.tfstates.asvm[key].workspace }}"
|
||||
storage_account = {
|
||||
name = "{{storage_account_level3.stdout|from_json|json_query('name')}}"
|
||||
}
|
||||
}
|
||||
{{ key }}_level4 = {
|
||||
name = "{{ resources.tfstates.asvm[key].workspace }}"
|
||||
storage_account = {
|
||||
name = "{{storage_account_level4.stdout|from_json|json_query('name')}}"
|
||||
}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
### Generate asvm for {{ asvm_folder }}
|
||||
|
||||
```bash
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
ARM_SKIP_PROVIDER_REGISTRATION=true && rover \
|
||||
{% if config.platform_identity.azuread_identity_mode != "logged_in_user" %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_subscription_creation_landingzones.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ destination_path }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates["asvm"][asvm_folder].subscriptions.tfstate }} \
|
||||
--workspace {{ config.tfstates["asvm"][asvm_folder].workspace }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates["asvm"][asvm_folder].subscriptions.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
rover logout
|
||||
|
||||
```
|
||||
Once you have executed the rover apply to create the subscription, you need to re-execute the rover ignite to generate the instructions for the next steps.
|
||||
|
||||
Note you need to logout and login as a caf_maintainer group member
|
||||
|
||||
```bash
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
rover ignite \
|
||||
--playbook /tf/caf/starter/templates/landingzones/ansible.yaml \
|
||||
-e base_templates_folder={{ base_templates_folder }} \
|
||||
-e resource_template_folder={{ resource_template_folder }} \
|
||||
-e config_folder={{ config_folder }} \
|
||||
-e destination_base_path={{ destination_base_path }} \
|
||||
-e config_folder_platform={{ config_folder_platform }}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1 @@
|
|||
yaml support for level coming soon.
|
|
@ -0,0 +1,277 @@
|
|||
- name: CAF Terraform - Generate Azure Subscription Vending Machine (asvm) configuration files
|
||||
hosts: localhost
|
||||
vars:
|
||||
connectivity_virtual_wan: "{{ lookup('file', '{{ config_folder }}/connectivity_virtual_wan.yaml') | from_yaml }}"
|
||||
connectivity_virtual_hub: "{{ lookup('file', '{{ config_folder }}/connectivity_virtual_hub.yaml') | from_yaml }}"
|
||||
connectivity_firewall: "{{ lookup('file', '{{ config_folder }}/connectivity_firewall.yaml') | from_yaml }}"
|
||||
connectivity_firewall_policies: "{{ lookup('file', '{{ config_folder }}/connectivity_firewall_policies.yaml') | from_yaml }}"
|
||||
connectivity_vpn_sites: "{{ lookup('file', '{{ config_folder }}/connectivity_vpn_sites.yaml') | from_yaml }}"
|
||||
connectivity_vpn_gateway_connections: "{{ lookup('file', '{{ config_folder }}/connectivity_vpn_gateway_connections.yaml') | from_yaml }}"
|
||||
connectivity_express_routes: "{{ lookup('file', '{{ config_folder }}/connectivity_express_routes.yaml') | from_yaml }}"
|
||||
connectivity_express_route_peerings: "{{ lookup('file', '{{ config_folder }}/connectivity_express_route_peerings.yaml') | from_yaml }}"
|
||||
identity: "{{ lookup('file', '{{ config_folder }}/identity.yaml') | from_yaml }}"
|
||||
management: "{{ lookup('file', '{{ config_folder }}/management.yaml') | from_yaml }}"
|
||||
subscriptions: "{{ lookup('file', '{{ config_folder }}/subscriptions.yaml') | from_yaml }}"
|
||||
mg: "{{ lookup('file', '{{ config_folder }}/eslz/archetype_config_overrides.caf.platform.yaml') | from_yaml }}"
|
||||
mg_custom: "{{ lookup('file', '{{ config_folder }}/eslz/custom_landing_zones.caf.platform.yaml') | from_yaml }}"
|
||||
mg_struture: "{{ lookup('file', '{{ config_folder }}/eslz/structure.caf.platform.yaml') | from_yaml }}"
|
||||
tfstates: "{{ lookup('file', '{{ config_folder }}/tfstates.yaml') | from_yaml }}"
|
||||
base_templates_folder: "{{ base_templates_folder }}"
|
||||
boostrap_launchpad: boostrap_launchpad | default(false)
|
||||
deploy_subscriptions: deploy_subscriptions | default(false)
|
||||
|
||||
|
||||
tasks:
|
||||
- name: "Get latest cache folder"
|
||||
set_fact:
|
||||
job_cache_base_path: "/home/vscode/.terraform.cache"
|
||||
|
||||
- name: "Creates cache directory"
|
||||
file:
|
||||
path: "{{ job_cache_base_path }}/launchpad"
|
||||
state: directory
|
||||
|
||||
- name: "Load variable for platform config"
|
||||
include_vars:
|
||||
name: config
|
||||
dir: "{{config_folder_platform | default(config_folder)}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "caf.platform.yaml|tfstates.caf.yaml|tfstates.yaml"
|
||||
|
||||
- name: "Content of config"
|
||||
debug:
|
||||
msg: "{{config}}"
|
||||
|
||||
#
|
||||
# Level 0
|
||||
#
|
||||
|
||||
## launchpad
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] launchpad"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
vars:
|
||||
base_folder: "launchpad"
|
||||
level: "level0"
|
||||
subscription_key: launchpad
|
||||
|
||||
## credentials
|
||||
- name: "[{{ level }}-{{ base_folder }}] Setup credentials"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
- config.platform_identity.azuread_identity_mode == "service_principal"
|
||||
- launchpad_tfstate_exists.rc == 0
|
||||
vars:
|
||||
base_folder: "credentials"
|
||||
level: "level0"
|
||||
subscription_key: launchpad_credentials
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when:
|
||||
- config.platform_identity.azuread_identity_mode == "logged_in_user"
|
||||
- launchpad_tfstate_exists.rc == 0
|
||||
vars:
|
||||
base_folder: "credentials"
|
||||
level: "level0"
|
||||
|
||||
## billing_subscription_role_delegations
|
||||
- name: "[{{ level }}-{{ base_folder }}] Configure subscription role delegations"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when: ((config.caf_terraform.billing_subscription_role_delegations is defined) and (config.platform_identity.azuread_identity_mode == "service_principal") and (launchpad_tfstate_exists.rc == 0) and (credentials_tfstate_exists is not skipped))
|
||||
vars:
|
||||
base_folder: "billing_subscription_role_delegations"
|
||||
level: "level0"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when:
|
||||
- level0_billing_subscription_role_delegations is skipped
|
||||
vars:
|
||||
base_folder: "billing_subscription_role_delegations"
|
||||
level: "level0"
|
||||
|
||||
|
||||
#
|
||||
# Level 1
|
||||
#
|
||||
|
||||
## subscriptions
|
||||
- name: "{{ level }}-{{ base_folder }} | Create platform subscriptions"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when: (config.platform_core_setup.enterprise_scale.subscription_deployment_mode == "dedicated_new" and config.platform_identity.azuread_identity_mode != "logged_in_user" and launchpad_tfstate_exists is succeeded and credentials_tfstate_exists is succeeded)
|
||||
vars:
|
||||
base_folder: "subscriptions"
|
||||
level: "level1"
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when:
|
||||
- level1_subscriptions is skipped
|
||||
vars:
|
||||
base_folder: "subscriptions"
|
||||
level: "level1"
|
||||
|
||||
## management
|
||||
- name: "{{ level }}-{{ base_folder }} | Management services"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
- (config.platform_management.enable | bool)
|
||||
# - (level1_subscriptions is not skipped)
|
||||
# - platform_subscriptions_details is defined
|
||||
|
||||
vars:
|
||||
base_folder: "management"
|
||||
level: "level1"
|
||||
subscription_key: management
|
||||
|
||||
## identity
|
||||
- name: "{{ level }}-{{ base_folder }} | Identity services"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
# - config.platform_core_setup.enterprise_scale.subscription_deployment_mode != "single_reuse"
|
||||
- launchpad_tfstate_exists is not skipped
|
||||
- credentials_tfstate_exists is not skipped
|
||||
- level1_subscriptions is not skipped
|
||||
- platform_subscriptions_details is defined
|
||||
- identity.level1 is defined
|
||||
|
||||
vars:
|
||||
base_folder: "identity"
|
||||
level: "level1"
|
||||
|
||||
## eslz
|
||||
- name: "{{ level }}-{{ base_folder }} | Enterprise-scale services"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
- (config.platform_core_setup.enterprise_scale.enable | bool)
|
||||
- ( (config.platform_core_setup.enterprise_scale.enable | bool) and (level1_subscriptions is not skipped) ) or (config.platform_core_setup.enterprise_scale.subscription_deployment_mode == "single_reuse")
|
||||
- (platform_subscriptions_details is defined) or (config.platform_core_setup.enterprise_scale.subscription_deployment_mode == "single_reuse")
|
||||
|
||||
vars:
|
||||
base_folder: "eslz"
|
||||
level: "level1"
|
||||
|
||||
|
||||
#
|
||||
# Level 2
|
||||
#
|
||||
|
||||
## asvm
|
||||
- name: "{{ level }}-{{ base_folder }} | Azure Subscription Vending Machine (asvm)"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
- config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine
|
||||
- launchpad_azuread_groups is defined
|
||||
vars:
|
||||
base_folder: "asvm"
|
||||
level: "level2"
|
||||
subscription_key: asvm
|
||||
|
||||
## Connectivity
|
||||
- name: "{{ level }}-{{ base_folder }} | Connectivity services"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
- ( (config.networking_topology.deployment_option == "virtual_wan") or (config.platform_identity.azuread_identity_mode == 'logged_in_user') )
|
||||
- (platform_subscriptions_details is defined) or (config.platform_core_setup.enterprise_scale.subscription_deployment_mode == "single_reuse")
|
||||
vars:
|
||||
base_folder: "connectivity"
|
||||
level: "level2"
|
||||
folders:
|
||||
- virtual_wan
|
||||
|
||||
## identity
|
||||
- name: "{{ level }}-{{ base_folder }} | Identity services"
|
||||
import_tasks: "{{ level }}/{{ base_folder }}/ansible.yaml"
|
||||
when:
|
||||
- config.platform_core_setup.enterprise_scale.subscription_deployment_mode != "single_reuse"
|
||||
- launchpad_tfstate_exists is not skipped
|
||||
- credentials_tfstate_exists is not skipped
|
||||
- level1_subscriptions is not skipped
|
||||
- (platform_subscriptions_details is defined) or (config.platform_core_setup.enterprise_scale.subscription_deployment_mode == "single_reuse")
|
||||
|
||||
vars:
|
||||
base_folder: "identity"
|
||||
level: "level2"
|
||||
|
||||
## Platform readme
|
||||
|
||||
- name: "[{{ base_templates_folder }}] readme"
|
||||
ansible.builtin.template:
|
||||
src: "{{ base_templates_folder }}/readme.md"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/readme.md"
|
||||
force: yes
|
||||
|
||||
#
|
||||
# Formatting & Linters
|
||||
#
|
||||
|
||||
- name: Terraform Formatting
|
||||
shell: |
|
||||
terraform fmt -recursive {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}
|
||||
|
||||
# - name: Level 2 - identity
|
||||
# hosts: localhost
|
||||
# vars:
|
||||
# config: "{{ lookup('file', '{{ config_folder }}/platform.yaml') | from_yaml }}"
|
||||
# identity: "{{ lookup('file', '{{ config_folder }}/identity.yaml') | from_yaml }}"
|
||||
# connectivity_virtual_wan: "{{ lookup('file', '{{ config_folder }}/connectivity_virtual_wan.yaml') | from_yaml }}"
|
||||
# connectivity_virtual_hub: "{{ lookup('file', '{{ config_folder }}/connectivity_virtual_hub.yaml') | from_yaml }}"
|
||||
# connectivity_firewall: "{{ lookup('file', '{{ config_folder }}/connectivity_firewall.yaml') | from_yaml }}"
|
||||
# connectivity_firewall_policies: "{{ lookup('file', '{{ config_folder }}/connectivity_firewall_policies.yaml') | from_yaml }}"
|
||||
# cidr: "{{ lookup('file', '{{ config_folder }}/cidr.yaml') | from_yaml }}"
|
||||
# tfstates: "{{ lookup('file', '{{ config_folder }}/tfstates.yaml') | from_yaml }}"
|
||||
# base_templates_folder: /tf/caf/templates/platform
|
||||
# base_folder: identity
|
||||
# level: level2
|
||||
# folders:
|
||||
# - virtual_wan
|
||||
|
||||
|
||||
# tasks:
|
||||
# - name: Creates {{ level }} directory
|
||||
# file:
|
||||
# path: "{{ config.configuration_folders.destination_base_path }}{{ config.configuration_folders.destination_relative_path }}/{{ level }}"
|
||||
# state: directory
|
||||
|
||||
# - name: Creates {{ base_folder }} directory strcture
|
||||
# file:
|
||||
# path: "{{ config.configuration_folders.destination_base_path }}{{ config.configuration_folders.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
# state: directory
|
||||
|
||||
# - name: "{{ base_folder }} - Readme"
|
||||
# ansible.builtin.template:
|
||||
# src: "{{ item }}"
|
||||
# dest: "{{ config.configuration_folders.destination_base_path }}{{ config.configuration_folders.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
# force: yes
|
||||
# with_fileglob:
|
||||
# - "{{ level }}/{{ base_folder }}/*.md"
|
||||
|
||||
# - name: "{{ base_folder }} - adds"
|
||||
# include_tasks: "{{ base_templates_folder }}/{{ level }}/{{ base_folder }}/platform.yaml"
|
||||
|
||||
|
||||
|
||||
# #
|
||||
# # Pipelines
|
||||
# #
|
||||
# - name: Pipelines
|
||||
# hosts: localhost
|
||||
# vars:
|
||||
# config: "{{ lookup('file', '{{ config_folder }}/platform.yaml') | from_yaml }}"
|
||||
# connectivity: "{{ lookup('file', '{{ config_folder }}/connectivity.yaml') | from_yaml }}"
|
||||
# cidr: "{{ lookup('file', '{{ config_folder }}/cidr.yaml') | from_yaml }}"
|
||||
# tfstates: "{{ lookup('file', '{{ config_folder }}/tfstates.yaml') | from_yaml }}"
|
||||
# base_templates_folder: /tf/caf/templates/platform
|
||||
# base_folder: pipelines
|
||||
|
||||
# tasks:
|
||||
# - import_tasks: "{{ base_folder }}/platform.yaml"
|
||||
# - debug: msg="You can now proceed to the next steps and execute the deployment. Refer to the readme in {{ config.configuration_folders.destination_base_path }}{{ config.configuration_folders.destination_relative_path }}/README.md"
|
|
@ -0,0 +1,51 @@
|
|||
## Introduction
|
||||
This directory contains details around the configurations which are deployed to the config. All the components are deployed in a layered approach.
|
||||
|
||||
### Level 0
|
||||
Deployment Elements | Resources Deployed
|
||||
---------------------| ------------------
|
||||
bootstrap | This steps bootstrap the environment with gitops prod subscription, deploys caf subscription, and create service principals.
|
||||
launchpad | This step deploys launchpad store terraform states and manage deployments.
|
||||
|
||||
### Level 1
|
||||
|
||||
Deployment Elements | Resources Deployed
|
||||
----------------------------- | ------------------
|
||||
Platform- Subscriptions | Deploys platform subscriptions such as management, conncetivity, and identity
|
||||
management | Foundation resources to management subscription such as service health alerts, log analytics
|
||||
gitops | This directory hosts the Azure DevOps configurations such as Azure DevOps projects, pipelines variable groups
|
||||
Identity | This hosts the identities for the pipelines and identies are pushed to vault after created
|
||||
Enterprise scale - Platform | Deploys eslz resources suych as management groups, custom roles, policies, and map that to management groups
|
||||
|
||||
|
||||
### Level 2
|
||||
|
||||
Deployment Elements | Resources Deployed
|
||||
------------------------------------| ------------------
|
||||
Connectivity - Platform | Deploys platform connectivity resources Resource Groups, Firewalls, app gateways, Vnet, Public IPs
|
||||
Connectivity - hub_connection | Deploys virtual hub connections for the virtual networks
|
||||
gitops | Deploys Azure DevOps agents, aks configurations, identity etc.
|
||||
|
||||
|
||||
# Deployment steps
|
||||
Below are the steps to be followed for deployment.
|
||||
|
||||
## Login the Azure AD Tenant
|
||||
|
||||
```bash
|
||||
az account clear
|
||||
rover login -t <tenant_name>
|
||||
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
||||
|
||||
You need a developer machine configured with the dependencies.
|
||||
|
||||
| Repo | Description |
|
||||
|---------------------------------------------------------------------------------------------------|------------------------------------------------------------|
|
||||
| [Azure Windows 10](../../../documentation/maintainer/set_azure_devops_vm.md) | Azure Windows 10 Virtual Desktop with docker engine, wsl2 and vscode |
|
||||
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when: config.configuration_folders.platform.cleanup_destination | bool
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Creates directory"
|
||||
when: config.caf_terraform.billing_subscription_role_delegations.enable == true
|
||||
register: level0_billing_subscription_role_delegations
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: directory
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] subscription role delegation"
|
||||
when: config.caf_terraform.billing_subscription_role_delegations.enable == true
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.tfvars.j2"
|
||||
- "{{ level }}/{{ base_folder }}/*.md"
|
|
@ -0,0 +1,12 @@
|
|||
landingzone = {
|
||||
backend_type = "{{ caf_terraform.launchpad.backend_type | default("azurerm")}}"
|
||||
global_settings_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
level = "{{ config.tfstates.platform.launchpad.level }}"
|
||||
key = "{{ config.tfstates.platform.billing_subscription_role_delegations.lz_key_name }}"
|
||||
tfstates = {
|
||||
{{ config.tfstates.platform.launchpad.lz_key_name }} = {
|
||||
level = "current"
|
||||
tfstate = "{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
### billing_subscription_role_delegations
|
||||
Set-up the subscription delegations for platform and landingzone subscriptions
|
||||
|
||||
```bash
|
||||
# Login to the subscription {{ config.caf_terraform.launchpad.subscription_name }} with the user {{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner }}
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
rover \
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/level0/billing_subscription_role_delegations \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.billing_subscription_role_delegations.tfstate }} \
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-launchpad \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.platform.billing_subscription_role_delegations.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
rover logout
|
||||
|
||||
```
|
||||
|
||||
# Run rover ignite to generate the next level configuration files
|
||||
|
||||
To execute this step you need to login with on of the CAF maintainers:
|
||||
{% for maintainer in config.platform_identity.caf_platform_maintainers %}
|
||||
- {{ maintainer }}
|
||||
{% endfor %}
|
||||
|
||||
```bash
|
||||
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
rover ignite \
|
||||
--playbook /tf/caf/starter/templates/platform/ansible.yaml \
|
||||
-e base_templates_folder={{ base_templates_folder }} \
|
||||
-e resource_template_folder={{resource_template_folder}} \
|
||||
-e config_folder={{ config_folder }}
|
||||
|
||||
```
|
||||
|
||||
# Next steps
|
||||
|
||||
When you have successfully deployed the level0 components, you can move to the next step.
|
||||
|
||||
[Deploy the subscriptions](../../level1/subscriptions/readme.md)
|
|
@ -0,0 +1,24 @@
|
|||
subscription_billing_role_assignments = {
|
||||
# Delegated accounts who can create subscriptions.
|
||||
# Used by Gitops pipelines
|
||||
subscription_creators = {
|
||||
billing_account_name = "{{ config.caf_terraform.billing_subscription_role_delegations.billing_account_name }}"
|
||||
enrollment_account_name = "{{ config.caf_terraform.billing_subscription_role_delegations.enrollment_account_name }}"
|
||||
billing_role_definition_name = "Enrollment account subscription creator"
|
||||
|
||||
principals = {
|
||||
azuread_service_principals = {
|
||||
subscription_creation_platform = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
key = "subscription_creation_platform"
|
||||
}
|
||||
subscription_creation_landingzones = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
key = "subscription_creation_landingzones"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
- name: "[{{ level }}-{{ base_folder }}] - Set variables"
|
||||
set_fact:
|
||||
destination_path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] - Load variable for launchpad"
|
||||
include_vars:
|
||||
name: resources
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "launchpad_credentials.yaml"
|
||||
|
||||
- debug:
|
||||
msg: "{{resources}}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when: config.configuration_folders.platform.cleanup_destination | bool
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Creates directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: directory
|
||||
|
||||
#
|
||||
# resource_groups
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resource_groups"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].resource_groups is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/resource_groups.tfvars.j2"
|
||||
#
|
||||
# azuread_credentials
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - credentials - azuread_credentials"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_credentials is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_credentials.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_applications
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - credentials - azuread_applications"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_applications is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_applications.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_credential_policies
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - credentials - azuread_credential_policies"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_credential_policies is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_credential_policies.tfvars.j2"
|
||||
|
||||
#
|
||||
# azuread_service_principals
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - credentials - azuread_service_principals"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].azuread_service_principals is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/azuread_service_principals.tfvars.j2"
|
||||
|
||||
|
||||
#
|
||||
# keyvaults
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - credentials - keyvaults"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].keyvaults is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/keyvaults.tfvars.j2"
|
||||
|
||||
#
|
||||
# keyvault_access_policies
|
||||
#
|
||||
- name: "[{{ level }}-{{ subscription_key }}] - credentials - keyvault_access_policies"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].keyvault_access_policies is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/keyvault_access_policies.tfvars.j2"
|
||||
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] generate configuration files."
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.tfvars.j2"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] deploy."
|
||||
when: boostrap_launchpad | bool
|
||||
shell: |
|
||||
/tf/rover/rover.sh \
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ tfstates.launchpad_credentials.tfstate }} \
|
||||
-launchpad \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-a apply
|
||||
args:
|
||||
warn: no
|
||||
|
||||
- debug:
|
||||
msg: "{{ keyvaults.cred_subscription_creation_platform.vault_uri }}"
|
||||
when: credentials_tfstate_exists.rc == 0
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] generate configuration files."
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.md"
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
# Store output attributes into keyvault secret
|
||||
# Those values are used by the rover to connect the current remote state and
|
||||
# identity the lower level
|
||||
dynamic_keyvault_secrets = {
|
||||
cred_ea_account_owner = { # ea account owner
|
||||
account_owner_username = {
|
||||
secret_name = "account-owner-username"
|
||||
value = ""
|
||||
}
|
||||
account_owner_password = {
|
||||
secret_name = "account-owner-password"
|
||||
value = ""
|
||||
}
|
||||
tenant_id = {
|
||||
secret_name = "tenant-id"
|
||||
value = "{{ config.caf_terraform.launchpad.tenant_id }}" # {{ config.platform_identity.tenant_name }} Tenant
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
landingzone = {
|
||||
backend_type = "{{ caf_terraform.launchpad.backend_type | default("azurerm")}}"
|
||||
global_settings_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
level = "{{ config.tfstates.platform.launchpad.level }}"
|
||||
key = "{{ config.tfstates.platform.launchpad_credentials.lz_key_name }}"
|
||||
tfstates = {
|
||||
{{ config.tfstates.platform.launchpad.lz_key_name }} = {
|
||||
level = "current"
|
||||
tfstate = "{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
### Generate launchpad credentials
|
||||
|
||||
```bash
|
||||
# For manual bootstrap:
|
||||
# Login to the subscription {{ config.caf_terraform.launchpad.subscription_name }} with the user {{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner }}
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
rover \
|
||||
{% if ((config.platform_identity.azuread_identity_mode != "logged_in_user") and (credentials_tfstate_exists.rc == 0)) %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_identity.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.launchpad_credentials.tfstate }} \
|
||||
-launchpad \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.platform.launchpad_credentials.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
rover logout
|
||||
|
||||
```
|
||||
|
||||
|
||||
# Next steps
|
||||
|
||||
When you have successfully deployed the launchpad you can move to the next step.
|
||||
|
||||
[Deploy the billing subscription role delegation](../billing_subscription_role_delegations/readme.md)
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
#
|
||||
# Services supported: subscriptions, storage accounts and resource groups
|
||||
# Can assign roles to: AD groups, AD object ID, AD applications, Managed identities
|
||||
#
|
||||
|
||||
role_mapping = {
|
||||
built_in_role_mapping = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
resource_groups = {
|
||||
sp_credentials = {
|
||||
"Contributor" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"identity"
|
||||
]
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
- name: "[{{ level }}-{{ base_folder }}] - Set variables"
|
||||
set_fact:
|
||||
destination_path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] - Load variable for launchpad"
|
||||
include_vars:
|
||||
name: resources
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "launchpad.yaml|level0.yaml|configuration.caf.platform.yaml"
|
||||
|
||||
- debug:
|
||||
msg: "{{resources}}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when: config.configuration_folders.platform.cleanup_destination | bool
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Creates directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: directory
|
||||
|
||||
|
||||
#
|
||||
# resource_groups
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - resource_groups"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].resource_groups is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/resource_groups.tfvars.j2"
|
||||
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] launchpad"
|
||||
ansible.builtin.template:
|
||||
src: "{{ level }}/{{ base_folder }}/{{ item }}.tfvars.j2"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item }}.tfvars"
|
||||
force: yes
|
||||
loop:
|
||||
- dynamic_secrets
|
||||
- global_settings
|
||||
- keyvaults
|
||||
- landingzone
|
||||
- role_mappings
|
||||
- storage_accounts
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Clean-up identity files"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item }}.tfvars"
|
||||
state: absent
|
||||
when: config.platform_identity.azuread_identity_mode == "logged_in_user"
|
||||
loop:
|
||||
- azuread_api_permissions
|
||||
- azuread_applications
|
||||
- azuread_group_members
|
||||
- azuread_groups
|
||||
- azuread_roles
|
||||
- keyvault_policies
|
||||
- service_principals
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] lauchpad - identity - service_principal"
|
||||
ansible.builtin.template:
|
||||
src: "{{ level }}/{{ base_folder }}/{{ item }}.tfvars.j2"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item }}.tfvars"
|
||||
force: yes
|
||||
when: config.platform_identity.azuread_identity_mode != 'logged_in_user'
|
||||
loop:
|
||||
- azuread_api_permissions
|
||||
- azuread_applications
|
||||
- azuread_group_members
|
||||
- azuread_groups
|
||||
- azuread_roles
|
||||
- keyvault_policies
|
||||
- service_principals
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Deploy the launchpad"
|
||||
when: boostrap_launchpad | bool | default(false)
|
||||
shell: |
|
||||
/tf/rover/rover.sh \
|
||||
-lz /tf/caf/landingzones/caf_launchpad \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.launchpad.tfstate }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-launchpad \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-a apply
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get tfstate account name"
|
||||
register: launchpad_storage_account
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='{{ config.tfstates.platform.launchpad.level }}' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name}[0]" -o json | jq -r .name
|
||||
|
||||
- debug:
|
||||
msg: "{{launchpad_storage_account}}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get launchpad tfstate details"
|
||||
register: launchpad_tfstate_exists
|
||||
ignore_errors: true
|
||||
shell: |
|
||||
az storage blob download \
|
||||
--name "{{ config.tfstates.platform.launchpad.tfstate }}" \
|
||||
--account-name "{{ launchpad_storage_account.stdout | default('') }}" \
|
||||
--container-name "{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }}" \
|
||||
--auth-mode "login" \
|
||||
--file "~/.terraform.cache/launchpad/{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get subscription_creation_landingzones details"
|
||||
when:
|
||||
- launchpad_tfstate_exists.rc == 0
|
||||
- config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine
|
||||
shell: "cat ~/.terraform.cache/launchpad/{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
register: launchpad_tfstate
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get launchpad json data"
|
||||
when:
|
||||
- launchpad_tfstate_exists.rc == 0
|
||||
- config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine
|
||||
set_fact:
|
||||
scljsondata: "{{ launchpad_tfstate.stdout | from_json }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] set launchpad_azuread_groups"
|
||||
when:
|
||||
- launchpad_tfstate_exists.rc == 0
|
||||
- config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine
|
||||
set_fact:
|
||||
launchpad_azuread_groups: "{{ scljsondata | json_query(path) }}"
|
||||
vars:
|
||||
path: 'outputs.objects.value.launchpad.azuread_groups'
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get credentials tfstate details"
|
||||
register: credentials_tfstate_exists
|
||||
ignore_errors: true
|
||||
shell: |
|
||||
az storage blob download \
|
||||
--name "{{ config.tfstates.platform.launchpad_credentials.tfstate }}" \
|
||||
--account-name "{{ launchpad_storage_account.stdout }}" \
|
||||
--container-name "{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }}" \
|
||||
--auth-mode "login" \
|
||||
--file "~/.terraform.cache/launchpad/{{ config.tfstates.platform.launchpad_credentials.tfstate }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get launchpad_credentials details"
|
||||
when: credentials_tfstate_exists.rc == 0
|
||||
shell: "cat ~/.terraform.cache/launchpad/{{ config.tfstates.platform.launchpad_credentials.tfstate }}"
|
||||
register: launchpad_credentials
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get launchpad_credentials json data"
|
||||
when: credentials_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
credjsondata: "{{ launchpad_credentials.stdout | from_json }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] set keyvaults"
|
||||
when: credentials_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
keyvaults: "{{ credjsondata | json_query(path) }}"
|
||||
vars:
|
||||
path: 'outputs.objects.value.launchpad_credentials_rotation.keyvaults'
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] cleanup"
|
||||
when: credentials_tfstate_exists.rc == 0
|
||||
file:
|
||||
path: "~/.terraform.cache/launchpad/{{ config.tfstates.platform.launchpad_credentials.tfstate }}"
|
||||
state: absent
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] cleanup"
|
||||
when: launchpad_tfstate_exists.rc == 0
|
||||
file:
|
||||
path: "~/.terraform.cache/launchpad/{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
state: absent
|
||||
|
||||
# Update readme
|
||||
- name: "[{{ level }}-{{ base_folder }}] launchpad - readme"
|
||||
ansible.builtin.template:
|
||||
src: "{{ level }}/{{ base_folder }}/readme.md"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/readme.md"
|
||||
force: yes
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
|
||||
azuread_api_permissions = {
|
||||
level0 = {
|
||||
microsoft_graph = {
|
||||
resource_app_id = "00000003-0000-0000-c000-000000000000"
|
||||
resource_access = {
|
||||
AppRoleAssignment_ReadWrite_All = {
|
||||
id = "06b708a9-e830-4db3-a914-8e69da51d44f"
|
||||
type = "Role"
|
||||
}
|
||||
DelegatedPermissionGrant_ReadWrite_All = {
|
||||
id = "8e8e4742-1d95-4f68-9d56-6ee75648c72a"
|
||||
type = "Role"
|
||||
}
|
||||
DelegatedPermissionGrant_ReadWrite_All = {
|
||||
id = "18a4783c-866b-4cc7-a460-3d5e5662c884"
|
||||
type = "Role"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
identity = {
|
||||
active_directory_graph = {
|
||||
resource_app_id = "00000002-0000-0000-c000-000000000000"
|
||||
resource_access = {
|
||||
Application_ReadWrite_OwnedBy = {
|
||||
id = "824c81eb-e3f8-4ee6-8f6d-de7f50d565b7"
|
||||
type = "Role"
|
||||
}
|
||||
Directory_ReadWrite_All = {
|
||||
id = "78c8a3c8-a07e-4b9e-af1b-b5ccab50a175"
|
||||
type = "Role"
|
||||
}
|
||||
}
|
||||
}
|
||||
microsoft_graph = {
|
||||
resource_app_id = "00000003-0000-0000-c000-000000000000"
|
||||
resource_access = {
|
||||
AppRoleAssignment_ReadWrite_All = {
|
||||
id = "06b708a9-e830-4db3-a914-8e69da51d44f"
|
||||
type = "Role"
|
||||
}
|
||||
DelegatedPermissionGrant_ReadWrite_All = {
|
||||
id = "8e8e4742-1d95-4f68-9d56-6ee75648c72a"
|
||||
type = "Role"
|
||||
}
|
||||
GroupReadWriteAll = {
|
||||
id = "62a82d76-70ea-41e2-9197-370581804d09"
|
||||
type = "Role"
|
||||
}
|
||||
RoleManagement_ReadWrite_Directory = {
|
||||
id = "9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8"
|
||||
type = "Role"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
azuread_applications = {
|
||||
level0 = {
|
||||
application_name = "sp-caf-level0"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
identity = {
|
||||
application_name = "sp-caf-identity"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
management = {
|
||||
application_name = "sp-caf-management"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
eslz = {
|
||||
application_name = "sp-caf-eslz"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
connectivity = {
|
||||
application_name = "sp-caf-connectivity"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
subscription_creation_platform = {
|
||||
application_name = "sp-caf-subscription-creation-platform"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
subscription_creation_landingzones = {
|
||||
application_name = "sp-caf-subscription-creation-landingzones"
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
azuread_groups_membership = {
|
||||
caf_platform_maintainers = {
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
object_ids = {
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
members = {
|
||||
user_principal_names = [
|
||||
"{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner }}",
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user'%}
|
||||
{% for user in config.platform_identity.caf_platform_maintainers %}
|
||||
"{{ user }}",
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
caf_platform_contributors = {
|
||||
members = {
|
||||
user_principal_names = [
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' and config.platform_identity.caf_platform_contributors is defined %}
|
||||
{% for user in config.platform_identity.caf_platform_contributors %}
|
||||
"{{ user }}",
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
azuread_groups = {
|
||||
caf_platform_maintainers = {
|
||||
name = "caf-platform-maintainers"
|
||||
description = "High privileged group to run all CAF deployments from vscode. Can be used to bootstrap or troubleshoot deployments."
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
caf_platform_contributors = {
|
||||
name = "caf-platform-contributors"
|
||||
description = "Can only execute terraform plans for level1 and level2. They can test platform improvements and propose PR."
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
level0 = {
|
||||
name = "caf-level0"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["level0"]
|
||||
}
|
||||
}
|
||||
|
||||
eslz = {
|
||||
name = "caf-eslz"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["eslz"]
|
||||
}
|
||||
}
|
||||
|
||||
identity = {
|
||||
name = "caf-identity"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["identity"]
|
||||
}
|
||||
}
|
||||
|
||||
management = {
|
||||
name = "caf-management"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["management"]
|
||||
}
|
||||
}
|
||||
|
||||
connectivity = {
|
||||
name = "caf-connectivity"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["connectivity"]
|
||||
}
|
||||
}
|
||||
|
||||
subscription_creation_platform = {
|
||||
name = "caf-subscription_creation_platform"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["subscription_creation_platform"]
|
||||
}
|
||||
}
|
||||
|
||||
subscription_creation_landingzones = {
|
||||
name = "caf-subscription_creation_landingzones"
|
||||
prevent_duplicate_name = true
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id is defined %}
|
||||
owners = ["{{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner_object_id }}"] // EA account
|
||||
{% endif %}
|
||||
members = {
|
||||
azuread_service_principal_keys = ["subscription_creation_landingzones"]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# Available roles:
|
||||
# az rest --method Get --uri https://graph.microsoft.com/v1.0/directoryRoleTemplates -o json | jq -r .value[].displayName
|
||||
#
|
||||
azuread_roles = {
|
||||
azuread_service_principals = {
|
||||
level0 = {
|
||||
roles = [
|
||||
"Privileged Role Administrator",
|
||||
"Application Administrator",
|
||||
"Groups Administrator"
|
||||
]
|
||||
}
|
||||
identity = {
|
||||
roles = [
|
||||
"User Administrator",
|
||||
"Application Administrator",
|
||||
"Groups Administrator"
|
||||
]
|
||||
}
|
||||
subscription_creation_landingzones = {
|
||||
roles = [
|
||||
"Application Administrator",
|
||||
"Groups Administrator"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
# Store output attributes into keyvault secret
|
||||
# Those values are used by the rover to connect the current remote state and
|
||||
# identity the lower level
|
||||
dynamic_keyvault_secrets = {
|
||||
level0 = {
|
||||
subscription_id = {
|
||||
output_key = "client_config"
|
||||
attribute_key = "subscription_id"
|
||||
secret_name = "subscription-id"
|
||||
}
|
||||
tenant_id = {
|
||||
output_key = "client_config"
|
||||
attribute_key = "tenant_id"
|
||||
secret_name = "tenant-id"
|
||||
}
|
||||
}
|
||||
level1 = {
|
||||
lower_stg = {
|
||||
output_key = "storage_accounts"
|
||||
resource_key = "level0"
|
||||
attribute_key = "name"
|
||||
secret_name = "lower-storage-account-name"
|
||||
}
|
||||
lower_rg = {
|
||||
output_key = "resource_groups"
|
||||
resource_key = "level0"
|
||||
attribute_key = "name"
|
||||
secret_name = "lower-resource-group-name"
|
||||
}
|
||||
subscription_id = {
|
||||
output_key = "client_config"
|
||||
attribute_key = "subscription_id"
|
||||
secret_name = "subscription-id"
|
||||
}
|
||||
tenant_id = {
|
||||
output_key = "client_config"
|
||||
attribute_key = "tenant_id"
|
||||
secret_name = "tenant-id"
|
||||
}
|
||||
}
|
||||
level2 = {
|
||||
lower_stg = {
|
||||
output_key = "storage_accounts"
|
||||
resource_key = "level1"
|
||||
attribute_key = "name"
|
||||
secret_name = "lower-storage-account-name"
|
||||
}
|
||||
lower_rg = {
|
||||
output_key = "resource_groups"
|
||||
resource_key = "level1"
|
||||
attribute_key = "name"
|
||||
secret_name = "lower-resource-group-name"
|
||||
}
|
||||
subscription_id = {
|
||||
output_key = "client_config"
|
||||
attribute_key = "subscription_id"
|
||||
secret_name = "subscription-id"
|
||||
}
|
||||
tenant_id = {
|
||||
output_key = "client_config"
|
||||
attribute_key = "tenant_id"
|
||||
secret_name = "tenant-id"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# naming convention settings
|
||||
# for more settings on naming convention, please refer to the provider documentation: https://github.com/aztfmod/terraform-provider-azurecaf
|
||||
#
|
||||
# passthrough means the default CAF naming convention is not applied and you are responsible
|
||||
# of the unicity of the names you are giving. the CAF provider will clear out
|
||||
passthrough = {{ config.caf_terraform.naming_convention.passthrough | string | lower }}
|
||||
# adds random chars at the end of the names produced by the provider
|
||||
# Do not change the following values once the launchpad deployed.
|
||||
|
||||
# Enable tag inheritance (can be changed)
|
||||
inherit_tags = {{ config.caf_terraform.naming_convention.inherit_tags | string | lower }}
|
||||
# When passthrough is set to false, define the number of random characters to add to the names
|
||||
random_length = {{ config.caf_terraform.naming_convention.random_length }}
|
||||
|
||||
# Default region. When not set to a resource it will use that value
|
||||
default_region = "{{ config.caf_terraform.launchpad.default_region_key }}"
|
||||
|
||||
# You can reference the regions by using region1, region2 or set your own keys
|
||||
regions = {
|
||||
{% for key in config.caf_terraform.launchpad.regions.keys() %}
|
||||
{{ key }} = "{{ config.caf_terraform.launchpad.regions[key].name }}"
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
# Rover will adjust some tags to enable the discovery of the launchpad.
|
||||
launchpad_key_names = {
|
||||
keyvault = "level0"
|
||||
tfstates = [
|
||||
"level0",
|
||||
"level1",
|
||||
"level2"
|
||||
]
|
||||
}
|
||||
|
||||
# Global tags
|
||||
tags = {
|
||||
ApplicationOwner = "sre"
|
||||
BusinessUnit = "sre"
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
keyvault_access_policies = {
|
||||
# A maximum of 16 access policies per keyvault
|
||||
level0 = {
|
||||
sp_level0 = {
|
||||
azuread_group_key = "level0"
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
identity = {
|
||||
azuread_group_key = "identity"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
}
|
||||
|
||||
# A maximum of 16 access policies per keyvault
|
||||
level1 = {
|
||||
sp_level0 = {
|
||||
# Allow level1 devops agent to be managed from agent pool level0
|
||||
azuread_group_key = "level0"
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
identity = {
|
||||
azuread_group_key = "identity"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
management = {
|
||||
azuread_group_key = "management"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
eslz = {
|
||||
azuread_group_key = "eslz"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
subscription_creation_platform = {
|
||||
azuread_group_key = "subscription_creation_platform"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
}
|
||||
# A maximum of 16 access policies per keyvault
|
||||
level2 = {
|
||||
sp_level0 = {
|
||||
azuread_group_key = "level0"
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
connectivity = {
|
||||
azuread_group_key = "connectivity"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
identity = {
|
||||
azuread_group_key = "identity"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
management = {
|
||||
azuread_group_key = "management"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
{% if config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine %}
|
||||
subscription_creation_landingzones = {
|
||||
azuread_group_key = "subscription_creation_landingzones"
|
||||
secret_permissions = ["Get"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
keyvaults = {
|
||||
level0 = {
|
||||
name = "{{ resources.subscriptions[subscription_key].keyvaults.level0.name }}"
|
||||
resource_group_key = "{{ resources.subscriptions[subscription_key].keyvaults.level0.resource_group_key }}"
|
||||
sku_name = "{{ config.platform_core_setup.sku.keyvault}}"
|
||||
tags = {
|
||||
tfstate = "level0"
|
||||
environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
caf_tfstate = "level0"
|
||||
caf_environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
}
|
||||
|
||||
creation_policies = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
caf_platform_maintainers = {
|
||||
azuread_group_key = "caf_platform_maintainers"
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
logged_in_user = {
|
||||
# if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
|
||||
# More examples in /examples/keyvault
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
level1 = {
|
||||
name = "{{ resources.subscriptions[subscription_key].keyvaults.level1.name }}"
|
||||
resource_group_key = "{{ resources.subscriptions[subscription_key].keyvaults.level1.resource_group_key }}"
|
||||
sku_name = "{{ config.platform_core_setup.sku.keyvault}}"
|
||||
tags = {
|
||||
tfstate = "level1"
|
||||
environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
caf_tfstate = "level1"
|
||||
caf_environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
}
|
||||
|
||||
creation_policies = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
caf_platform_maintainers = {
|
||||
azuread_group_key = "caf_platform_maintainers"
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
logged_in_user = {
|
||||
# if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
|
||||
# More examples in /examples/keyvault
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
level2 = {
|
||||
name = "{{ resources.subscriptions[subscription_key].keyvaults.level2.name }}"
|
||||
resource_group_key = "{{ resources.subscriptions[subscription_key].keyvaults.level2.resource_group_key }}"
|
||||
sku_name = "{{ config.platform_core_setup.sku.keyvault}}"
|
||||
tags = {
|
||||
tfstate = "level2"
|
||||
environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
caf_tfstate = "level2"
|
||||
caf_environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
}
|
||||
|
||||
creation_policies = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
caf_platform_maintainers = {
|
||||
azuread_group_key = "caf_platform_maintainers"
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
logged_in_user = {
|
||||
# if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
|
||||
# More examples in /examples/keyvault
|
||||
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
landingzone = {
|
||||
backend_type = "{{ caf_terraform.launchpad.backend_type | default("azurerm")}}"
|
||||
level = "{{ config.tfstates.platform.launchpad.level }}"
|
||||
key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
# Launchpad - {{ config.caf_terraform.launchpad.caf_environment }}
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
This scenario requires the following privileges:
|
||||
|
||||
| Component | Privileges |
|
||||
|--------------------|--------------------|
|
||||
| Active Directory | None |
|
||||
| Azure subscription | Subscription owner |
|
||||
|
||||
## Deployment
|
||||
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations is defined %}
|
||||
### Pre-requisite
|
||||
|
||||
Elevate your credentials to the tenant root level to have enough privileges to create the management group hierarchy.
|
||||
|
||||
```bash
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.enable %}
|
||||
# Login to the subscription {{ config.caf_terraform.launchpad.subscription_name }} with the user {{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner }}
|
||||
{% else %}
|
||||
# Login to the subscription {{ config.caf_terraform.launchpad.subscription_name }} with an account owner.
|
||||
{% endif %}
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
az rest --method post --url "/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01"
|
||||
|
||||
```
|
||||
{% endif %}
|
||||
|
||||
### Launchpad
|
||||
|
||||
```bash
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations is defined %}
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.enable %}
|
||||
# Login to the subscription {{ config.caf_terraform.launchpad.subscription_name }} with the user {{ config.caf_terraform.billing_subscription_role_delegations.azuread_user_ea_account_owner }}
|
||||
{% else %}
|
||||
# Login to the subscription {{ config.caf_terraform.launchpad.subscription_name }} with an account owner.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
rover login -t {{ config.platform_identity.tenant_name }} -s {{ config.caf_terraform.launchpad.subscription_id }}
|
||||
|
||||
cd /tf/caf/landingzones
|
||||
git fetch origin
|
||||
git checkout {{ config.gitops.caf_landingzone_branch }}
|
||||
|
||||
rover \
|
||||
-lz /tf/caf/landingzones/caf_launchpad \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.launchpad.tfstate }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-launchpad \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.platform.launchpad.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
```
|
||||
|
||||
## Architecture diagram
|
||||
![Launchpad demo](../../../../../../documentation/img/launchpad-demo.PNG)
|
||||
|
||||
|
||||
# Next steps
|
||||
|
||||
When you have successfully deployed the launchpad you can move to the next step.
|
||||
|
||||
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations is defined %}
|
||||
{% if config.caf_terraform.billing_subscription_role_delegations.enable %}
|
||||
[Deploy the credentials landing zone](../credentials/readme.md)
|
||||
{% else %}
|
||||
[Deploy the management services](../../level1/management/readme.md)
|
||||
{% endif %}
|
||||
{% else %}
|
||||
[Deploy the management services](../../level1/management/readme.md)
|
||||
{% endif %}
|
|
@ -0,0 +1,198 @@
|
|||
|
||||
#
|
||||
# Services supported: subscriptions, storage accounts and resource groups
|
||||
# Can assign roles to: AD groups, AD object ID, AD applications, Managed identities
|
||||
#
|
||||
|
||||
role_mapping = {
|
||||
built_in_role_mapping = {
|
||||
{% if config.platform_core_setup %}
|
||||
management_group = {
|
||||
root = {
|
||||
"User Access Administrator" = {
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
azuread_groups = {
|
||||
keys = ["level0"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
"Management Group Contributor" = {
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
azuread_groups = {
|
||||
keys = ["eslz", "caf_platform_maintainers"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
"Owner" = {
|
||||
{% if config.platform_identity.azuread_identity_mode == 'logged_in_user' %}
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
azuread_groups = {
|
||||
keys = ["eslz", "caf_platform_maintainers"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
subscriptions = {
|
||||
logged_in_subscription = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
azuread_groups = {
|
||||
keys = ["level0", "caf_platform_maintainers", "subscription_creation_platform"]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Reader" = {
|
||||
azuread_groups = {
|
||||
keys = ["identity"]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
resource_groups = {
|
||||
level0 = {
|
||||
"Reader" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"identity",
|
||||
"subscription_creation_platform"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
level1 = {
|
||||
"Reader" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"identity",
|
||||
"management",
|
||||
"eslz",
|
||||
"subscription_creation_platform"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
level2 = {
|
||||
"Reader" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"identity",
|
||||
"connectivity",
|
||||
"management",
|
||||
"subscription_creation_landingzones"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
storage_accounts = {
|
||||
level0 = {
|
||||
"Storage Blob Data Contributor" = {
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
azuread_groups = {
|
||||
keys = ["level0", "caf_platform_maintainers", "identity"]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Storage Blob Data Reader" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"management",
|
||||
"eslz",
|
||||
"subscription_creation_platform"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
level1 = {
|
||||
"Storage Blob Data Contributor" = {
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"caf_platform_maintainers",
|
||||
"identity",
|
||||
"management",
|
||||
"eslz",
|
||||
"subscription_creation_platform"
|
||||
]
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Storage Blob Data Reader" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"connectivity",
|
||||
{% if config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine %}
|
||||
"level0"
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
level2 = {
|
||||
"Storage Blob Data Contributor" = {
|
||||
logged_in = {
|
||||
keys = ["user"]
|
||||
}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
"identity",
|
||||
"connectivity",
|
||||
"management",
|
||||
"caf_platform_maintainers",
|
||||
{% if config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine %}
|
||||
"level0"
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
"Storage Blob Data Reader" = {
|
||||
azuread_groups = {
|
||||
keys = [
|
||||
{% if config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine %}
|
||||
"subscription_creation_landingzones"
|
||||
{% endif %}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
azuread_service_principals = {
|
||||
# Manage the deployment of the level0
|
||||
level0 = {
|
||||
azuread_application = {
|
||||
key = "level0"
|
||||
}
|
||||
}
|
||||
# Manage the deployment of Enterprise Scale
|
||||
eslz = {
|
||||
azuread_application = {
|
||||
key = "eslz"
|
||||
}
|
||||
}
|
||||
# Manage the deployment of the connectivity services
|
||||
connectivity = {
|
||||
azuread_application = {
|
||||
key = "connectivity"
|
||||
}
|
||||
}
|
||||
# Manage the deployment of the shared services
|
||||
management = {
|
||||
azuread_application = {
|
||||
key = "management"
|
||||
}
|
||||
}
|
||||
# Manage the deployment of the identity services
|
||||
identity = {
|
||||
azuread_application = {
|
||||
key = "identity"
|
||||
}
|
||||
}
|
||||
# Has delegation to create platform subscriptions
|
||||
subscription_creation_platform = {
|
||||
azuread_application = {
|
||||
key = "subscription_creation_platform"
|
||||
}
|
||||
}
|
||||
# Has delegation to create landingzone subscriptions
|
||||
subscription_creation_landingzones = {
|
||||
azuread_application = {
|
||||
key = "subscription_creation_landingzones"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
storage_accounts = {
|
||||
level0 = {
|
||||
name = "{{ resources.subscriptions[subscription_key].storage_accounts.level0.name }}"
|
||||
resource_group_key = "{{ resources.subscriptions[subscription_key].storage_accounts.level0.resource_group_key }}"
|
||||
account_kind = "BlobStorage"
|
||||
account_tier = "Standard"
|
||||
account_replication_type = "{{ config.caf_terraform.launchpad.account_replication_type }}"
|
||||
tags = {
|
||||
## Those tags must never be changed after being set as they are used by the rover to locate the launchpad and the tfstates.
|
||||
# Only adjust the environment value at creation time
|
||||
tfstate = "level0"
|
||||
environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
launchpad = "launchpad"
|
||||
caf_environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
caf_launchpad = "launchpad"
|
||||
caf_tfstate = "level0"
|
||||
##
|
||||
}
|
||||
blob_properties = {
|
||||
versioning_enabled = {{ config.caf_terraform.launchpad.blob_versioning_enabled | string | lower | default('true') }}
|
||||
container_delete_retention_policy = {{ config.caf_terraform.launchpad.container_delete_retention_policy | default(7) }}
|
||||
delete_retention_policy = {{ config.caf_terraform.launchpad.delete_retention_policy | default(7) }}
|
||||
}
|
||||
containers = {
|
||||
{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }} = {
|
||||
name = "{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
level1 = {
|
||||
name = "{{ resources.subscriptions[subscription_key].storage_accounts.level1.name }}"
|
||||
resource_group_key = "{{ resources.subscriptions[subscription_key].storage_accounts.level1.resource_group_key }}"
|
||||
account_kind = "BlobStorage"
|
||||
account_tier = "Standard"
|
||||
account_replication_type = "{{ config.caf_terraform.launchpad.account_replication_type }}"
|
||||
tags = {
|
||||
# Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates.
|
||||
tfstate = "level1"
|
||||
environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
launchpad = "launchpad"
|
||||
caf_environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
caf_launchpad = "launchpad"
|
||||
caf_tfstate = "level1"
|
||||
}
|
||||
blob_properties = {
|
||||
versioning_enabled = {{ config.caf_terraform.launchpad.blob_versioning_enabled | string | lower | default('true') }}
|
||||
container_delete_retention_policy = {{ config.caf_terraform.launchpad.container_delete_retention_policy | default(7) }}
|
||||
delete_retention_policy = {{ config.caf_terraform.launchpad.delete_retention_policy | default(7) }}
|
||||
}
|
||||
containers = {
|
||||
{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }} = {
|
||||
name = "{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
level2 = {
|
||||
name = "{{ resources.subscriptions[subscription_key].storage_accounts.level2.name }}"
|
||||
resource_group_key = "{{ resources.subscriptions[subscription_key].storage_accounts.level2.resource_group_key }}"
|
||||
account_kind = "BlobStorage"
|
||||
account_tier = "Standard"
|
||||
account_replication_type = "{{ config.caf_terraform.launchpad.account_replication_type }}"
|
||||
tags = {
|
||||
# Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates.
|
||||
tfstate = "level2"
|
||||
environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
launchpad = "launchpad"
|
||||
caf_environment = "{{ config.caf_terraform.launchpad.caf_environment }}"
|
||||
caf_launchpad = "launchpad"
|
||||
caf_tfstate = "level2"
|
||||
}
|
||||
blob_properties = {
|
||||
versioning_enabled = {{ config.caf_terraform.launchpad.blob_versioning_enabled | string | lower | default('true') }}
|
||||
container_delete_retention_policy = {{ config.caf_terraform.launchpad.container_delete_retention_policy | default(7) }}
|
||||
delete_retention_policy = {{ config.caf_terraform.launchpad.delete_retention_policy | default(7) }}
|
||||
}
|
||||
containers = {
|
||||
{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }} = {
|
||||
name = "{{ config.tfstates.platform.launchpad.workspace | default('tfstate') }}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# Cloud Adoption Framework landing zones for Terraform - Starter template
|
||||
|
||||
Place here your production environment configuration files.
|
|
@ -0,0 +1,58 @@
|
|||
- name: "{{ level }}-{{ base_folder }} | Clean-up base directory"
|
||||
shell: |
|
||||
rm -rf "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
when:
|
||||
- config.platform_core_setup.enterprise_scale.enable
|
||||
- config.platform_core_setup.enterprise_scale.clean_up_destination_folder
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | Creates directory structure"
|
||||
shell: mkdir -p "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/lib/{{ item.path }}"
|
||||
with_filetree: "{{ level }}/{{ base_folder }}/lib/{{ config.platform_core_setup.enterprise_scale.private_lib.version_to_deploy }}"
|
||||
when: item.state == 'directory'
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | Tfvars"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.j2"
|
||||
- "{{ level }}/{{ base_folder }}/*.md"
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | Lib - archetypes - built-in"
|
||||
ansible.builtin.template:
|
||||
src: "{{ base_templates_folder }}/{{ level }}/eslz/lib/{{ config.platform_core_setup.enterprise_scale.private_lib.version_to_deploy }}/archetype_definitions/archetype_definition_template.json.j2"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/lib/archetype_definitions/archetype_definition_{{ mg.archetype_definitions[item].archetype_id }}.json"
|
||||
force: yes
|
||||
loop: "{{ mg.archetype_definitions.keys() }}"
|
||||
loop_control:
|
||||
loop_var: item
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | Lib - archetypes - custom"
|
||||
when:
|
||||
- mg_custom.archetype_definitions is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ base_templates_folder }}/{{ level }}/eslz/lib/{{ config.platform_core_setup.enterprise_scale.private_lib.version_to_deploy }}/archetype_definitions/custom_landing_zone_template.json.j2"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/lib/archetype_definitions/archetype_definition_{{ mg_custom.archetype_definitions[item].archetype_id }}.json"
|
||||
force: yes
|
||||
loop: "{{ mg_custom.archetype_definitions.keys() }}"
|
||||
loop_control:
|
||||
loop_var: item
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | Lib"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item.src }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/lib/{{ item.path }}"
|
||||
force: yes
|
||||
with_filetree: "{{ config_folder }}/eslz/lib"
|
||||
when: item.state == 'file' and config.platform_core_setup.enterprise_scale.update_lib_folder
|
||||
|
||||
- name: "{{ level }}-{{ base_folder }} | overrides"
|
||||
when:
|
||||
- mg_custom.archetype_definitions is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/lib/{{ config.platform_core_setup.enterprise_scale.private_lib.version_to_deploy }}/*.tfvars.j2"
|
|
@ -0,0 +1,28 @@
|
|||
landingzone = {
|
||||
backend_type = "{{ caf_terraform.launchpad.backend_type | default("azurerm")}}"
|
||||
global_settings_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
level = "level1"
|
||||
key = "{{ config.tfstates.platform.eslz.lz_key_name }}"
|
||||
tfstates = {
|
||||
{{ config.tfstates.platform.launchpad.lz_key_name }} = {
|
||||
level = "lower"
|
||||
tfstate = "{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
}
|
||||
{{ config.tfstates.platform.management.lz_key_name }} = {
|
||||
level = "current"
|
||||
tfstate = "{{ config.tfstates.platform.management.tfstate }}"
|
||||
}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
{{ config.tfstates.platform.platform_subscriptions.lz_key_name }} = {
|
||||
level = "current"
|
||||
tfstate = "{{ config.tfstates.platform.platform_subscriptions.tfstate }}"
|
||||
}
|
||||
{% endif %}
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
{{ config.tfstates.platform.identity.lz_key_name }} = {
|
||||
level = "current"
|
||||
tfstate = "{{ config.tfstates.platform.identity.tfstate }}"
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
library_path = "../../../../{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/lib"
|
||||
root_id = "{{ config.platform_core_setup.enterprise_scale.management_group_prefix }}"
|
||||
root_name = "{{ config.platform_core_setup.enterprise_scale.management_group_name }}"
|
||||
deploy_core_landing_zones = {{ config.platform_core_setup.enterprise_scale.deploy_core_landing_zones | string | lower }}
|
||||
{% if (config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine | default(false)) and config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
reconcile_vending_subscriptions = true
|
||||
{% endif %}
|
|
@ -0,0 +1,97 @@
|
|||
archetype_config_overrides = {
|
||||
|
||||
root = {
|
||||
archetype_id = "root"
|
||||
parameters = {
|
||||
"Deny-Resource-Locations" = {
|
||||
"listOfAllowedLocations" = {
|
||||
value = [
|
||||
"{{ config.caf_terraform.launchpad.regions.region1.name }}",
|
||||
"{{ config.caf_terraform.launchpad.regions.region2.name }}"
|
||||
]
|
||||
}
|
||||
}
|
||||
"Deny-RSG-Locations" = {
|
||||
"listOfAllowedLocations" = {
|
||||
value = [
|
||||
"{{ config.caf_terraform.launchpad.regions.region1.name }}",
|
||||
"{{ config.caf_terraform.launchpad.regions.region2.name }}"
|
||||
]
|
||||
}
|
||||
}
|
||||
"Deploy-Resource-Diag" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_region1"
|
||||
attribute_key = "id"
|
||||
}
|
||||
"profileName" = {
|
||||
value = "eslz-diagnostic-log"
|
||||
}
|
||||
}
|
||||
"Deploy-VM-Monitoring" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_region1"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
"Deploy-VMSS-Monitoring" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_region1"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
}
|
||||
access_control = {}
|
||||
} //root
|
||||
|
||||
landing-zones = {
|
||||
archetype_id = "landingzone"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
platform = {
|
||||
archetype_id = "platform"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
connectivity = {
|
||||
archetype_id = "platform_connectivity"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
identity = {
|
||||
archetype_id = "platform_identity"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
management = {
|
||||
archetype_id = "platform_management"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
decommissioned = {
|
||||
archetype_id = "es_decommissioned"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
sandboxes = {
|
||||
archetype_id = "es_sandboxes"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default archetypes
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/archetype_definitions
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"landingzone": {
|
||||
"policy_assignments": [
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"landingzone_corp": {
|
||||
"policy_assignments": [
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"landingzone_online": {
|
||||
"policy_assignments": [
|
||||
"Deploy-ASC-Defender"
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {
|
||||
"Deploy-ASC-Defender": {
|
||||
"pricingTierAppServices": "Free",
|
||||
"pricingTierVMs": "Free",
|
||||
"pricingTierSqlServers": "Standard",
|
||||
"pricingTierStorageAccounts": "Standard",
|
||||
"pricingTierContainerRegistry": "Free",
|
||||
"pricingTierKeyVaults": "Standard",
|
||||
"pricingTierKubernetesService": "Free",
|
||||
"pricingTierDns": "Free",
|
||||
"pricingTierArm": "Free"
|
||||
}
|
||||
},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"platform": {
|
||||
"policy_assignments": [
|
||||
"Deploy-ASC-Defender"
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {
|
||||
"Deploy-ASC-Defender": {
|
||||
"pricingTierAppServices": "Free",
|
||||
"pricingTierVMs": "Free",
|
||||
"pricingTierSqlServers": "Standard",
|
||||
"pricingTierStorageAccounts": "Standard",
|
||||
"pricingTierContainerRegistry": "Free",
|
||||
"pricingTierKeyVaults": "Standard",
|
||||
"pricingTierKubernetesService": "Free",
|
||||
"pricingTierDns": "Free",
|
||||
"pricingTierArm": "Free"
|
||||
}
|
||||
},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"platform_connectivity": {
|
||||
"policy_assignments": [
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"platform_identity": {
|
||||
"policy_assignments": [
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"platform_management": {
|
||||
"policy_assignments": [
|
||||
],
|
||||
"policy_definitions": [
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {},
|
||||
"access_control": {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
{
|
||||
"root": {
|
||||
"policy_assignments": [
|
||||
"Deploy-Resource-Diag",
|
||||
"Deny-Resource-Locations",
|
||||
"Deny-RSG-Locations"
|
||||
],
|
||||
"policy_definitions": [
|
||||
"Append-KV-SoftDelete",
|
||||
"Deny-AA-child-resources",
|
||||
"Deny-AppGW-Without-WAF",
|
||||
"Deny-Private-DNS-Zones",
|
||||
"Deny-PublicEndpoint-Aks",
|
||||
"Deny-PublicEndpoint-CosmosDB",
|
||||
"Deny-PublicEndpoint-KeyVault",
|
||||
"Deny-PublicEndpoint-MariaDB",
|
||||
"Deny-PublicEndpoint-MySQL",
|
||||
"Deny-PublicEndpoint-PostgreSql",
|
||||
"Deny-PublicEndpoint-Sql",
|
||||
"Deny-PublicEndpoint-Storage",
|
||||
"Deny-PublicIP",
|
||||
"Deny-RDP-From-Internet",
|
||||
"Deny-Subnet-Without-Nsg",
|
||||
"Deny-Subnet-Without-Udr",
|
||||
"Deny-VNET-Peer-Cross-Sub",
|
||||
"Deny-VNet-Peering",
|
||||
"Deploy-ASC-Standard",
|
||||
"Deploy-Budget",
|
||||
"Deploy-DDoSProtection",
|
||||
"Deploy-Diagnostics-AA",
|
||||
"Deploy-Diagnostics-ACI",
|
||||
"Deploy-Diagnostics-ACR",
|
||||
"Deploy-Diagnostics-ActivityLog",
|
||||
"Deploy-Diagnostics-AKS",
|
||||
"Deploy-Diagnostics-AnalysisService",
|
||||
"Deploy-Diagnostics-ApiForFHIR",
|
||||
"Deploy-Diagnostics-APIMgmt",
|
||||
"Deploy-Diagnostics-ApplicationGateway",
|
||||
"Deploy-Diagnostics-Batch",
|
||||
"Deploy-Diagnostics-CDNEndpoints",
|
||||
"Deploy-Diagnostics-CognitiveServices",
|
||||
"Deploy-Diagnostics-CosmosDB",
|
||||
"Deploy-Diagnostics-Databricks",
|
||||
"Deploy-Diagnostics-DataExplorerCluster",
|
||||
"Deploy-Diagnostics-DataFactory",
|
||||
"Deploy-Diagnostics-DataLakeStore",
|
||||
"Deploy-Diagnostics-DLAnalytics",
|
||||
"Deploy-Diagnostics-EventGridSub",
|
||||
"Deploy-Diagnostics-EventGridSystemTopic",
|
||||
"Deploy-Diagnostics-EventGridTopic",
|
||||
"Deploy-Diagnostics-EventHub",
|
||||
"Deploy-Diagnostics-ExpressRoute",
|
||||
"Deploy-Diagnostics-Firewall",
|
||||
"Deploy-Diagnostics-FrontDoor",
|
||||
"Deploy-Diagnostics-Function",
|
||||
"Deploy-Diagnostics-HDInsight",
|
||||
"Deploy-Diagnostics-iotHub",
|
||||
"Deploy-Diagnostics-KeyVault",
|
||||
"Deploy-Diagnostics-LoadBalancer",
|
||||
"Deploy-Diagnostics-LogicAppsISE",
|
||||
"Deploy-Diagnostics-LogicAppsWF",
|
||||
"Deploy-Diagnostics-MariaDB",
|
||||
"Deploy-Diagnostics-MediaService",
|
||||
"Deploy-Diagnostics-MlWorkspace",
|
||||
"Deploy-Diagnostics-MySQL",
|
||||
"Deploy-Diagnostics-NetworkSecurityGroups",
|
||||
"Deploy-Diagnostics-NIC",
|
||||
"Deploy-Diagnostics-PostgreSQL",
|
||||
"Deploy-Diagnostics-PowerBIEmbedded",
|
||||
"Deploy-Diagnostics-PublicIP",
|
||||
"Deploy-Diagnostics-RecoveryVault",
|
||||
"Deploy-Diagnostics-RedisCache",
|
||||
"Deploy-Diagnostics-Relay",
|
||||
"Deploy-Diagnostics-SearchServices",
|
||||
"Deploy-Diagnostics-ServiceBus",
|
||||
"Deploy-Diagnostics-SignalR",
|
||||
"Deploy-Diagnostics-SQLDBs",
|
||||
"Deploy-Diagnostics-SQLElasticPools",
|
||||
"Deploy-Diagnostics-SQLMI",
|
||||
"Deploy-Diagnostics-StreamAnalytics",
|
||||
"Deploy-Diagnostics-TimeSeriesInsights",
|
||||
"Deploy-Diagnostics-TrafficManager",
|
||||
"Deploy-Diagnostics-VirtualNetwork",
|
||||
"Deploy-Diagnostics-VM",
|
||||
"Deploy-Diagnostics-VMSS",
|
||||
"Deploy-Diagnostics-VNetGW",
|
||||
"Deploy-Diagnostics-WebServerFarm",
|
||||
"Deploy-Diagnostics-Website",
|
||||
"Deploy-Diagnostics-WVDAppGroup",
|
||||
"Deploy-Diagnostics-WVDHostPools",
|
||||
"Deploy-Diagnostics-WVDWorkspace",
|
||||
"Deploy-DNSZoneGroup-For-Blob-PrivateEndpoint",
|
||||
"Deploy-DNSZoneGroup-For-File-PrivateEndpoint",
|
||||
"Deploy-DNSZoneGroup-For-KeyVault-PrivateEndpoint",
|
||||
"Deploy-DNSZoneGroup-For-Queue-PrivateEndpoint",
|
||||
"Deploy-DNSZoneGroup-For-Sql-PrivateEndpoint",
|
||||
"Deploy-DNSZoneGroup-For-Table-PrivateEndpoint",
|
||||
"Deploy-FirewallPolicy",
|
||||
"Deploy-LA-Config",
|
||||
"Deploy-Log-Analytics",
|
||||
"Deploy-Nsg-FlowLogs-to-LA",
|
||||
"Deploy-Sql-AuditingSettings",
|
||||
"Deploy-Sql-SecurityAlertPolicies",
|
||||
"Deploy-Sql-Tde",
|
||||
"Deploy-Sql-vulnerabilityAssessments",
|
||||
"Deploy-Windows-DomainJoin"
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
"Deny-PublicEndpoints",
|
||||
"Deploy-Diag-LogAnalytics",
|
||||
"Deploy-Sql-Security"
|
||||
],
|
||||
"role_definitions": [
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {},
|
||||
"access_control": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
custom_landing_zones = {
|
||||
{{ config.eslz.root_id }}-corp = {
|
||||
display_name = "Corp"
|
||||
parent_management_group_id = "{{ config.eslz.root_id }}-landing-zones"
|
||||
archetype_config = {
|
||||
archetype_id = "landingzone_corp"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
subscriptions = {}
|
||||
subscription_ids = []
|
||||
}
|
||||
{{ config.eslz.root_id }}-online = {
|
||||
display_name = "Online"
|
||||
parent_management_group_id = "{{ config.eslz.root_id }}-landing-zones"
|
||||
archetype_config = {
|
||||
archetype_id = "landingzone_online"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
subscriptions = {}
|
||||
subscription_ids = []
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy assignments
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_assignments
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "CAF-Security-Benchmark",
|
||||
"type": "Microsoft.Authorization/policyAssignments",
|
||||
"apiVersion": "2019-09-01",
|
||||
"properties": {
|
||||
"description": "The Azure Security Benchmark initiative represents the policies and controls implementing security recommendations defined in Azure Security Benchmark v2, see https://aka.ms/azsecbm. This also serves as the Azure Security Center default policy initiative. You can directly assign this initiative, or manage its policies and compliance results within Azure Security Center.",
|
||||
"displayName": "Azure Security BenchMark",
|
||||
"notScopes": [],
|
||||
"parameters": {},
|
||||
"policyDefinitionId": "/providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8",
|
||||
"scope": "${current_scope_resource_id}",
|
||||
"enforcementMode": true
|
||||
},
|
||||
"location": "${default_location}",
|
||||
"identity": {
|
||||
"type": "None"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_definitions
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy set definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_set_definitions
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
|
||||
# List of the default role defitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/role_definitions
|
|
@ -0,0 +1,208 @@
|
|||
archetype_config_overrides = {
|
||||
|
||||
root = {
|
||||
archetype_id = "root"
|
||||
parameters = {
|
||||
"Allowed-Locations" = {
|
||||
"listOfAllowedLocations" = {
|
||||
values = [
|
||||
{% for key in config.caf_terraform.launchpad.regions.keys() %}
|
||||
"{{ config.caf_terraform.launchpad.regions[key].name }}",
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
}
|
||||
"Deny-RSG-Locations" = {
|
||||
"listOfAllowedLocations" = {
|
||||
values = [
|
||||
{% for key in config.caf_terraform.launchpad.regions.keys() %}
|
||||
"{{ config.caf_terraform.launchpad.regions[key].name }}",
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
}
|
||||
"Deploy-Resource-Diag" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
"profileName" = {
|
||||
value = "eslz-diagnostic-log"
|
||||
}
|
||||
}
|
||||
"Deploy-AzActivity-Log" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% if "VM" in config.platform_management.enable_monitoring %}
|
||||
"Deploy-VM-Monitoring" = {
|
||||
"logAnalytics_1" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if "VMSS" in config.platform_management.enable_monitoring %}
|
||||
"Deploy-VMSS-Monitoring" = {
|
||||
"logAnalytics_1" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if "Arc" in config.platform_management.enable_monitoring %}
|
||||
"Deploy-WS-Arc-Monitoring" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
"Deploy-LX-Arc-Monitoring" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
"Deploy-ASC-Defender" = {
|
||||
"emailSecurityContact" = {
|
||||
value = "{{ config.notifications.security_center_email_contact }}"
|
||||
}
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
{% for parameter_key in mg.archetype_definitions.root.policy_assignments["Deploy-ASC-Defender"].keys() %}
|
||||
"{{ parameter_key }}" = {
|
||||
value = "{{ mg.archetype_definitions.root.policy_assignments["Deploy-ASC-Defender"][parameter_key] }}"
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
access_control = {}
|
||||
} //root
|
||||
|
||||
landing-zones = {
|
||||
archetype_id = "landingzone"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"subscription_creation_landingzones"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
platform = {
|
||||
archetype_id = "platform"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
connectivity = {
|
||||
archetype_id = "platform_connectivity"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"connectivity"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% if config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine %}
|
||||
"[{{ config.platform_core_setup.enterprise_scale.management_group_prefix | upper }}-CONNECTIVITY] CAF-network-vhub-peering" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"subscription_creation_landingzones"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
identity = {
|
||||
archetype_id = "platform_identity"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"identity"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
management = {
|
||||
archetype_id = "platform_management"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"management"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
decommissioned = {
|
||||
archetype_id = "es_decommissioned"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
sandboxes = {
|
||||
archetype_id = "es_sandboxes"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
archetype_config_overrides = {
|
||||
{% for key, level in mg.archetype_definitions.items() %}
|
||||
{{ key }} = {
|
||||
archetype_id = "{{mg.archetype_definitions[key].archetype_id }}"
|
||||
{% if mg.archetype_definitions[key].policy_assignments is defined %}
|
||||
parameters = {
|
||||
{% for pa_key, pa_value in mg.archetype_definitions[key].policy_assignments.items() %}
|
||||
{% if pa_value is mapping %}
|
||||
"{{ pa_key }}" = {
|
||||
{% for attribute, attribute_value in pa_value.items() %}
|
||||
"{{attribute}}" = {
|
||||
{% if attribute_value is string %}
|
||||
value = "{{ attribute_value }}"
|
||||
{% elif attribute_value is boolean %}
|
||||
value = {{ attribute_value | string | lower }}
|
||||
{% elif attribute_value is number %}
|
||||
value = {{ attribute_value }}
|
||||
{% else %}
|
||||
{% if attribute_value is mapping %}
|
||||
{% for caf_key, caf_value in attribute_value.items() %}
|
||||
{{ caf_key }} = "{{ caf_value }}"
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
values = {{ attribute_value | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
parameters = {}
|
||||
{% endif %}
|
||||
{% if level.archetype_config.access_control is defined %}
|
||||
access_control = {
|
||||
{% for level_ac_key, level_ac in level.archetype_config.access_control.items() %}
|
||||
"{{level_ac_key}}" = {
|
||||
{% for level_role_key, level_role in level_ac.items() %}
|
||||
"{{ level_role_key }}" = {
|
||||
lz_key = "{{ level_role.lz_key }}"
|
||||
attribute_key = "{{ level_role.attribute_key }}"
|
||||
resource_keys = {{ level_role.resource_keys | replace('None','[]') | replace('\'','\"') }}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
access_control = {}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default archetypes
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/archetype_definitions
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"{{ mg.archetype_definitions[item].archetype_id }}": {
|
||||
"policy_assignments": [
|
||||
{% if mg.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"role_definitions": [
|
||||
{% if mg.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {
|
||||
},
|
||||
"access_control": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"{{ mg_custom.archetype_definitions[item].archetype_id }}": {
|
||||
"policy_assignments": [
|
||||
{% if mg.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"role_definitions": [
|
||||
{% if mg.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {
|
||||
},
|
||||
"access_control": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
custom_landing_zones = {
|
||||
{% for key, level in mg_custom.archetype_definitions.items() %}
|
||||
{{ config.platform_core_setup.enterprise_scale.management_group_prefix }}-{{ key }} = {
|
||||
display_name = "{{ mg_custom.archetype_definitions[key].display_name }}"
|
||||
parent_management_group_id = "{{ config.platform_core_setup.enterprise_scale.management_group_prefix }}-{{ mg_custom.archetype_definitions[key].parent_management_group_id }}"
|
||||
archetype_config = {
|
||||
archetype_id = "{{mg_custom.archetype_definitions[key].archetype_id }}"
|
||||
{% if mg_custom.archetype_definitions[key].policy_assignments is defined %}
|
||||
parameters = {
|
||||
{% for pa_key, pa_value in mg_custom.archetype_definitions[key].policy_assignments.items() %}
|
||||
{% if pa_value is mapping %}
|
||||
"{{ pa_key }}" = {
|
||||
{% for attribute, attribute_value in pa_value.items() %}
|
||||
"{{attribute}}" = {
|
||||
{% if attribute_value is string %}
|
||||
value = "{{ attribute_value }}"
|
||||
{% elif attribute_value is boolean %}
|
||||
value = {{ attribute_value | string | lower }}
|
||||
{% elif attribute_value is number %}
|
||||
value = {{ attribute_value }}
|
||||
{% else %}
|
||||
{% if attribute_value is mapping %}
|
||||
{% for caf_key, caf_value in attribute_value.items() %}
|
||||
{{ caf_key }} = "{{ caf_value }}"
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
values = {{ attribute_value | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
parameters = {}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[key].archetype_config.access_control is defined %}
|
||||
access_control = {
|
||||
{% for level_ac_key, level_ac in mg_custom.archetype_definitions[key].archetype_config.access_control.items() %}
|
||||
"{{level_ac_key}}" = {
|
||||
{% for level_role_key, level_role in level_ac.items() %}
|
||||
"{{ level_role_key }}" = {
|
||||
lz_key = "{{ level_role.lz_key }}"
|
||||
attribute_key = "{{ level_role.attribute_key }}"
|
||||
resource_keys = {{ level_role.resource_keys | replace('None','[]') | replace('\'','\"') }}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
access_control = {}
|
||||
{% endif %}
|
||||
}
|
||||
subscriptions = {}
|
||||
subscription_ids = []
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy assignments
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_assignments
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "aks-capability",
|
||||
"type": "Microsoft.Authorization/policyAssignments",
|
||||
"apiVersion": "2019-09-01",
|
||||
"properties": {
|
||||
"description": "Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for AKS Engine and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. (labelSelector example - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements)",
|
||||
"displayName": "Kubernetes cluster containers should only use allowed capabilities.",
|
||||
"notScopes": [],
|
||||
"parameters": {},
|
||||
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/c26596ff-4d70-4e6a-9a30-c2506bd2f80c",
|
||||
"scope": "${current_scope_resource_id}",
|
||||
"enforcementMode": true
|
||||
},
|
||||
"location": "${default_location}",
|
||||
"identity": {
|
||||
"type": "None"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "Allowed-Locations",
|
||||
"type": "Microsoft.Authorization/policyAssignments",
|
||||
"apiVersion": "2019-09-01",
|
||||
"properties": {
|
||||
"description": "Specifies the allowed locations (regions) where Resources can be deployed.",
|
||||
"displayName": "Limit allowed locations for Resources",
|
||||
"notScopes": [],
|
||||
"parameters": {},
|
||||
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
|
||||
"scope": "${current_scope_resource_id}",
|
||||
"enforcementMode": null
|
||||
},
|
||||
"location": "${default_location}",
|
||||
"identity": {
|
||||
"type": "None"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_definitions
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy set definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_set_definitions
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
|
||||
# List of the default role defitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/role_definitions
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "48ec94a9-9a14-488d-928d-5e73f96b335c",
|
||||
"type": "Microsoft.Authorization/roleDefinitions",
|
||||
"apiVersion": "2018-01-01-preview",
|
||||
"properties": {
|
||||
"roleName": "CAF-network-vhub-peering",
|
||||
"description": "Authorize vnet peerings to the vhub.",
|
||||
"type": "customRole",
|
||||
"permissions": [
|
||||
{
|
||||
"actions": [
|
||||
"Microsoft.Resources/subscriptions/resourceGroups/read",
|
||||
"Microsoft.Network/virtualHubs/read",
|
||||
"Microsoft.Network/virtualHubs/hubVirtualNetworkConnections/*"
|
||||
],
|
||||
"notActions": [
|
||||
],
|
||||
"dataActions": [],
|
||||
"notDataActions": []
|
||||
}
|
||||
],
|
||||
"assignableScopes": [
|
||||
"${current_scope_resource_id}"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
archetype_config_overrides = {
|
||||
|
||||
root = {
|
||||
archetype_id = "root"
|
||||
parameters = {
|
||||
"Allowed-Locations" = {
|
||||
"listOfAllowedLocations" = {
|
||||
values = [
|
||||
{% for key in config.caf_terraform.launchpad.regions.keys() %}
|
||||
"{{ config.caf_terraform.launchpad.regions[key].name }}",
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
}
|
||||
"Deny-RSG-Locations" = {
|
||||
"listOfAllowedLocations" = {
|
||||
values = [
|
||||
{% for key in config.caf_terraform.launchpad.regions.keys() %}
|
||||
"{{ config.caf_terraform.launchpad.regions[key].name }}",
|
||||
{% endfor %}
|
||||
]
|
||||
}
|
||||
}
|
||||
"Deploy-Resource-Diag" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
"profileName" = {
|
||||
value = "eslz-diagnostic-log"
|
||||
}
|
||||
}
|
||||
"Deploy-AzActivity-Log" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% if "VM" in config.platform_management.enable_monitoring %}
|
||||
"Deploy-VM-Monitoring" = {
|
||||
"logAnalytics_1" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if "VMSS" in config.platform_management.enable_monitoring %}
|
||||
"Deploy-VMSS-Monitoring" = {
|
||||
"logAnalytics_1" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% if "Arc" in config.platform_management.enable_monitoring %}
|
||||
"Deploy-WS-Arc-Monitoring" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
"Deploy-LX-Arc-Monitoring" = {
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
"Deploy-ASC-Defender" = {
|
||||
"emailSecurityContact" = {
|
||||
value = "{{ config.notifications.security_center_email_contact }}"
|
||||
}
|
||||
"logAnalytics" = {
|
||||
lz_key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
output_key = "diagnostics"
|
||||
resource_type = "log_analytics"
|
||||
resource_key = "central_logs_{{config.caf_terraform.launchpad.regions[config.caf_terraform.launchpad.default_region_key].slug}}"
|
||||
attribute_key = "id"
|
||||
}
|
||||
{% for parameter_key in mg.archetype_definitions.root.policy_assignments["Deploy-ASC-Defender"].keys() %}
|
||||
"{{ parameter_key }}" = {
|
||||
value = "{{ mg.archetype_definitions.root.policy_assignments["Deploy-ASC-Defender"][parameter_key] }}"
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
||||
access_control = {}
|
||||
} //root
|
||||
|
||||
landing-zones = {
|
||||
archetype_id = "landingzone"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"subscription_creation_landingzones"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
platform = {
|
||||
archetype_id = "platform"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
connectivity = {
|
||||
archetype_id = "platform_connectivity"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"connectivity"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% if config.platform_core_setup.enterprise_scale.enable_azure_subscription_vending_machine %}
|
||||
"[{{ config.platform_core_setup.enterprise_scale.management_group_prefix | upper }}-CONNECTIVITY] CAF-network-vhub-peering" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"subscription_creation_landingzones"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
identity = {
|
||||
archetype_id = "platform_identity"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"identity"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
management = {
|
||||
archetype_id = "platform_management"
|
||||
parameters = {}
|
||||
access_control = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
"Owner" = {
|
||||
"azuread_groups" = {
|
||||
lz_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
attribute_key = "id"
|
||||
resource_keys = [
|
||||
"management"
|
||||
]
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
|
||||
decommissioned = {
|
||||
archetype_id = "es_decommissioned"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
|
||||
sandboxes = {
|
||||
archetype_id = "es_sandboxes"
|
||||
parameters = {}
|
||||
access_control = {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
archetype_config_overrides = {
|
||||
{% for key, level in mg.archetype_definitions.items() %}
|
||||
{{ key }} = {
|
||||
archetype_id = "{{mg.archetype_definitions[key].archetype_id }}"
|
||||
{% if mg.archetype_definitions[key].policy_assignments is defined %}
|
||||
parameters = {
|
||||
{% for pa_key, pa_value in mg.archetype_definitions[key].policy_assignments.items() %}
|
||||
{% if pa_value is mapping %}
|
||||
"{{ pa_key }}" = {
|
||||
{% for attribute, attribute_value in pa_value.items() %}
|
||||
"{{attribute}}" = {
|
||||
{% if attribute_value is string %}
|
||||
value = "{{ attribute_value }}"
|
||||
{% elif attribute_value is boolean %}
|
||||
value = {{ attribute_value | string | lower }}
|
||||
{% elif attribute_value is number %}
|
||||
value = {{ attribute_value }}
|
||||
{% else %}
|
||||
{% if attribute_value is mapping %}
|
||||
{% for caf_key, caf_value in attribute_value.items() %}
|
||||
{{ caf_key }} = "{{ caf_value }}"
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
values = {{ attribute_value | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
parameters = {}
|
||||
{% endif %}
|
||||
{% if level.archetype_config.access_control is defined %}
|
||||
access_control = {
|
||||
{% for level_ac_key, level_ac in level.archetype_config.access_control.items() %}
|
||||
"{{level_ac_key}}" = {
|
||||
{% for level_role_key, level_role in level_ac.items() %}
|
||||
"{{ level_role_key }}" = {
|
||||
lz_key = "{{ level_role.lz_key }}"
|
||||
attribute_key = "{{ level_role.attribute_key }}"
|
||||
resource_keys = {{ level_role.resource_keys | replace('None','[]') | replace('\'','\"') }}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
access_control = {}
|
||||
{% endif %}
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default archetypes
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/archetype_definitions
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"{{ mg.archetype_definitions[item].archetype_id }}": {
|
||||
"policy_assignments": [
|
||||
{% if mg.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"role_definitions": [
|
||||
{% if mg.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {
|
||||
},
|
||||
"access_control": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"{{ mg_custom.archetype_definitions[item].archetype_id }}": {
|
||||
"policy_assignments": [
|
||||
{% if mg.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_assignments is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_assignments.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"policy_set_definitions": [
|
||||
{% if mg.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].policy_set_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].policy_set_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"role_definitions": [
|
||||
{% if mg.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[item].role_definitions is defined %}
|
||||
{% for key in mg_custom.archetype_definitions[item].role_definitions.keys() %}
|
||||
{% if loop.last %}
|
||||
"{{ key }}"
|
||||
{% else %}
|
||||
"{{ key }}",
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
],
|
||||
"archetype_config": {
|
||||
"parameters": {
|
||||
},
|
||||
"access_control": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
custom_landing_zones = {
|
||||
{% for key, level in mg_custom.archetype_definitions.items() %}
|
||||
{{ config.platform_core_setup.enterprise_scale.management_group_prefix }}-{{ key }} = {
|
||||
display_name = "{{ mg_custom.archetype_definitions[key].display_name }}"
|
||||
parent_management_group_id = "{{ config.platform_core_setup.enterprise_scale.management_group_prefix }}-{{ mg_custom.archetype_definitions[key].parent_management_group_id }}"
|
||||
archetype_config = {
|
||||
archetype_id = "{{mg_custom.archetype_definitions[key].archetype_id }}"
|
||||
{% if mg_custom.archetype_definitions[key].policy_assignments is defined %}
|
||||
parameters = {
|
||||
{% for pa_key, pa_value in mg_custom.archetype_definitions[key].policy_assignments.items() %}
|
||||
{% if pa_value is mapping %}
|
||||
"{{ pa_key }}" = {
|
||||
{% for attribute, attribute_value in pa_value.items() %}
|
||||
"{{attribute}}" = {
|
||||
{% if attribute_value is string %}
|
||||
value = "{{ attribute_value }}"
|
||||
{% elif attribute_value is boolean %}
|
||||
value = {{ attribute_value | string | lower }}
|
||||
{% elif attribute_value is number %}
|
||||
value = {{ attribute_value }}
|
||||
{% else %}
|
||||
{% if attribute_value is mapping %}
|
||||
{% for caf_key, caf_value in attribute_value.items() %}
|
||||
{{ caf_key }} = "{{ caf_value }}"
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
values = {{ attribute_value | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
parameters = {}
|
||||
{% endif %}
|
||||
{% if mg_custom.archetype_definitions[key].archetype_config.access_control is defined %}
|
||||
access_control = {
|
||||
{% for level_ac_key, level_ac in mg_custom.archetype_definitions[key].archetype_config.access_control.items() %}
|
||||
"{{level_ac_key}}" = {
|
||||
{% for level_role_key, level_role in level_ac.items() %}
|
||||
"{{ level_role_key }}" = {
|
||||
lz_key = "{{ level_role.lz_key }}"
|
||||
attribute_key = "{{ level_role.attribute_key }}"
|
||||
resource_keys = {{ level_role.resource_keys | replace('None','[]') | replace('\'','\"') }}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% else %}
|
||||
access_control = {}
|
||||
{% endif %}
|
||||
}
|
||||
subscriptions = {}
|
||||
subscription_ids = []
|
||||
}
|
||||
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy assignments
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_assignments
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "aks-capability",
|
||||
"type": "Microsoft.Authorization/policyAssignments",
|
||||
"apiVersion": "2019-09-01",
|
||||
"properties": {
|
||||
"description": "Restrict the capabilities to reduce the attack surface of containers in a Kubernetes cluster. This recommendation is part of CIS 5.2.8 and CIS 5.2.9 which are intended to improve the security of your Kubernetes environments. This policy is generally available for Kubernetes Service (AKS), and preview for AKS Engine and Azure Arc enabled Kubernetes. For more information, see https://aka.ms/kubepolicydoc. (labelSelector example - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#resources-that-support-set-based-requirements)",
|
||||
"displayName": "Kubernetes cluster containers should only use allowed capabilities.",
|
||||
"notScopes": [],
|
||||
"parameters": {},
|
||||
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/c26596ff-4d70-4e6a-9a30-c2506bd2f80c",
|
||||
"scope": "${current_scope_resource_id}",
|
||||
"enforcementMode": true
|
||||
},
|
||||
"location": "${default_location}",
|
||||
"identity": {
|
||||
"type": "None"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "Allowed-Locations",
|
||||
"type": "Microsoft.Authorization/policyAssignments",
|
||||
"apiVersion": "2019-09-01",
|
||||
"properties": {
|
||||
"description": "Specifies the allowed locations (regions) where Resources can be deployed.",
|
||||
"displayName": "Limit allowed locations for Resources",
|
||||
"notScopes": [],
|
||||
"parameters": {},
|
||||
"policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
|
||||
"scope": "${current_scope_resource_id}",
|
||||
"enforcementMode": null
|
||||
},
|
||||
"location": "${default_location}",
|
||||
"identity": {
|
||||
"type": "None"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_definitions
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
# List of the default policy set definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/policy_set_definitions
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
# Public documentation of the custom landingzones
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BUser-Guide%5D-Archetype-Definitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/wiki/%5BExamples%5D-Deploy-Custom-Landing-Zone-Archetypes
|
||||
|
||||
|
||||
# List of the default role defitions
|
||||
|
||||
https://github.com/Azure/terraform-azurerm-caf-enterprise-scale/tree/main/modules/archetypes/lib/role_definitions
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "48ec94a9-9a14-488d-928d-5e73f96b335c",
|
||||
"type": "Microsoft.Authorization/roleDefinitions",
|
||||
"apiVersion": "2018-01-01-preview",
|
||||
"properties": {
|
||||
"roleName": "CAF-network-vhub-peering",
|
||||
"description": "Authorize vnet peerings to the vhub.",
|
||||
"type": "customRole",
|
||||
"permissions": [
|
||||
{
|
||||
"actions": [
|
||||
"Microsoft.Resources/subscriptions/resourceGroups/read",
|
||||
"Microsoft.Network/virtualHubs/read",
|
||||
"Microsoft.Network/virtualHubs/hubVirtualNetworkConnections/*"
|
||||
],
|
||||
"notActions": [
|
||||
],
|
||||
"dataActions": [],
|
||||
"notDataActions": []
|
||||
}
|
||||
],
|
||||
"assignableScopes": [
|
||||
"${current_scope_resource_id}"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
# Enterprise scale
|
||||
|
||||
## Deploy Enterprise Scale
|
||||
|
||||
Note you need to adjust the branch to deploy Enterprise Scale to {{ config.platform_core_setup.enterprise_scale.private_lib[config.platform_core_setup.enterprise_scale.private_lib.version_to_deploy].caf_landingzone_branch }}
|
||||
|
||||
```bash
|
||||
az account clear
|
||||
# login a with a user member of the caf-platform-maintainers group
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
cd {{ config.configuration_folders.platform.destination_base_path }}/landingzones
|
||||
git fetch origin
|
||||
git checkout {{ config.platform_core_setup.enterprise_scale.private_lib[config.platform_core_setup.enterprise_scale.private_lib.version_to_deploy].caf_landingzone_branch }}
|
||||
|
||||
rover \
|
||||
{% if keyvaults is defined and config.platform_identity.azuread_identity_mode != "logged_in_user" %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_eslz.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz {{ config.configuration_folders.platform.destination_base_path }}/landingzones/caf_solution/add-ons/caf_eslz \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.eslz.tfstate }} \
|
||||
-log-severity ERROR \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.platform.eslz.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
```
|
||||
|
||||
# Next steps
|
||||
|
||||
[Deploy Connectivity](../../level2/connectivity/readme.md)
|
|
@ -0,0 +1,41 @@
|
|||
subscription_id_overrides = {
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
root = []
|
||||
{% else %}
|
||||
root = [
|
||||
"{{ config.caf_terraform.launchpad.subscription_id }}"
|
||||
]
|
||||
{% endif %}
|
||||
decommissioned = []
|
||||
sandboxes = []
|
||||
landing-zones = []
|
||||
platform = []
|
||||
connectivity = []
|
||||
management = []
|
||||
identity = []
|
||||
}
|
||||
|
||||
{% if config.platform_identity.azuread_identity_mode != 'logged_in_user' %}
|
||||
subscription_id_overrides_by_keys = {
|
||||
connectivity = {
|
||||
connectivity = {
|
||||
lz_key = "{{ config.tfstates.platform.platform_subscriptions.lz_key_name }}"
|
||||
key = "connectivity"
|
||||
}
|
||||
}
|
||||
management = {
|
||||
management = {
|
||||
lz_key = "{{ config.tfstates.platform.platform_subscriptions.lz_key_name }}"
|
||||
key = "management"
|
||||
}
|
||||
}
|
||||
identity = {
|
||||
identity = {
|
||||
lz_key = "{{ config.tfstates.platform.platform_subscriptions.lz_key_name }}"
|
||||
key = "identity"
|
||||
}
|
||||
}
|
||||
}
|
||||
{% else %}
|
||||
subscription_id_overrides_by_keys = {}
|
||||
{% endif %}
|
|
@ -0,0 +1,20 @@
|
|||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when: config.configuration_folders.platform.cleanup_destination | bool
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Creates directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: directory
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] generate configuration files."
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.tfvars.j2"
|
||||
- "{{ level }}/{{ base_folder }}/*.md"
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
azuread_groups = {
|
||||
{% for key, ad_group in identity.level1.azuread_groups.items() %}
|
||||
{{ key }} = {
|
||||
name = "{{ ad_group.name }}"
|
||||
{% if ad_group.description is defined %}
|
||||
description = "{{ ad_group.description }}"
|
||||
{% endif %}
|
||||
{% if ad_group.members is defined %}
|
||||
members = {
|
||||
{% if ad_group.members.user_principal_names is defined %}
|
||||
user_principal_names = {{ ad_group.members.user_principal_names | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% if ad_group.members.group_names is defined %}
|
||||
group_names = {{ ad_group.members.group_names | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% if ad_group.members.object_ids is defined %}
|
||||
object_ids = {{ ad_group.members.object_ids | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% if ad_group.members.group_keys is defined %}
|
||||
group_keys = {{ ad_group.members.group_keys | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
{% if ad_group.members.service_principal_keys is defined %}
|
||||
service_principal_keys = {{ ad_group.members.service_principal_keys | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
{% if ad_group.owners is defined %}
|
||||
owners = {
|
||||
{% if ad_group.owners.user_principal_names is defined %}
|
||||
user_principal_names = {{ ad_group.owners.user_principal_names | replace('None','[]') | replace('\'','\"') }}
|
||||
{% endif %}
|
||||
}
|
||||
{% endif %}
|
||||
prevent_duplicate_name = {{ ad_group.owners.prevent_duplicate_name | default(false) | string | lower }}
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
landingzone = {
|
||||
backend_type = "{{ caf_terraform.launchpad.backend_type | default("azurerm")}}"
|
||||
global_settings_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
level = "{{ config.tfstates.platform.identity.level }}"
|
||||
key = "{{ config.tfstates.platform.identity.lz_key_name }}"
|
||||
tfstates = {
|
||||
{{ config.tfstates.platform.launchpad.lz_key_name }} = {
|
||||
level = "lower"
|
||||
tfstate = "{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
# Identity
|
||||
Deploy the identity services
|
||||
|
||||
```bash
|
||||
#Note: close previous session if you logged with a different service principal using --impersonate-sp-from-keyvault-url
|
||||
rover logout
|
||||
|
||||
# login a with a user member of the caf-maintainers group
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
rover \
|
||||
{% if keyvaults is defined and config.platform_identity.azuread_identity_mode != "logged_in_user" %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_identity.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ platform_subscriptions_details.identity.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.identity.tfstate }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.platform.identity.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
```
|
||||
|
||||
|
||||
# Next steps
|
||||
|
||||
[Deploy Enterprise Scale](../../level1/eslz/readme.md)
|
|
@ -0,0 +1,5 @@
|
|||
resource_groups = {
|
||||
mgmt = {
|
||||
name = "mgmt"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
monitoring = {
|
||||
service_health_alerts = {
|
||||
enable_service_health_alerts = true
|
||||
name = "alerts"
|
||||
action_group_name = "actiongrp"
|
||||
shortname = "HealthAlerts"
|
||||
resource_group_key = "mgmt"
|
||||
|
||||
email_alert_settings = {
|
||||
{% for key in config.notifications.service_health_alerts.emails.keys() %}
|
||||
{{ key }} = {
|
||||
name = "email_alert_support1"
|
||||
email_address = "{{ config.notifications.service_health_alerts.emails[key].email_address }}"
|
||||
use_common_alert_schema = false
|
||||
}
|
||||
{% endfor %}
|
||||
} #add more email alerts by repeating the block.
|
||||
# webhook = {
|
||||
# teams = {
|
||||
# name = "servicehealth"
|
||||
# service_uri = ""
|
||||
# }
|
||||
# }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when:
|
||||
- config.configuration_folders.platform.cleanup_destination | bool
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Creates directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: directory
|
||||
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] - Set variables"
|
||||
set_fact:
|
||||
destination_path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] - Load variables"
|
||||
include_vars:
|
||||
name: resources
|
||||
dir: "{{config_folder}}"
|
||||
depth: 1
|
||||
ignore_unknown_extensions: true
|
||||
files_matching: "management.yaml|configuration.caf.platform.yaml"
|
||||
|
||||
#
|
||||
# resource_groups
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - resource_groups"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].resource_groups is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/resource_groups.tfvars.j2"
|
||||
|
||||
#
|
||||
# automation_accounts
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - automation_accounts"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].automation_accounts is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/automation_accounts.tfvars.j2"
|
||||
|
||||
#
|
||||
# service_health_alerts
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - service_health_alerts"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].service_health_alerts is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/servicehealth.tfvars.j2"
|
||||
|
||||
#
|
||||
# diagnostic_log_analytics
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - diagnostic_log_analytics"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].diagnostic_log_analytics is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/diagnostic_log_analytics.tfvars.j2"
|
||||
|
||||
#
|
||||
# diagnostic_storage_accounts
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - diagnostic_storage_accounts"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].diagnostic_storage_accounts is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/diagnostic_storage_accounts.tfvars.j2"
|
||||
|
||||
# diagnostics_definition
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - diagnostics_definition"
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/diagnostics_definition.tfvars.j2"
|
||||
|
||||
# diagnostics_destinations
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - diagnostics_destinations"
|
||||
when:
|
||||
- resources.subscriptions[subscription_key].diagnostics_destinations is defined
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ resource_template_folder }}/diagnostics_destinations.tfvars.j2"
|
||||
|
||||
#
|
||||
# Readme
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - resources - *.md"
|
||||
# when: always
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ destination_path }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.md"
|
||||
|
||||
#
|
||||
# Legacy calls
|
||||
#
|
||||
- name: "[{{ level }}-{{ base_folder }}] - generate configuration files."
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.tfvars.j2"
|
|
@ -0,0 +1,12 @@
|
|||
landingzone = {
|
||||
backend_type = "{{ caf_terraform.launchpad.backend_type | default("azurerm")}}"
|
||||
global_settings_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
level = "{{ config.tfstates.platform.management.level }}"
|
||||
key = "{{ config.tfstates.platform.management.lz_key_name }}"
|
||||
tfstates = {
|
||||
{{ config.tfstates.platform.launchpad.lz_key_name }} = {
|
||||
level = "lower"
|
||||
tfstate = "{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
# Management
|
||||
Deploy the management services
|
||||
|
||||
```bash
|
||||
#Note: close previous session if you logged with a different service principal using --impersonate-sp-from-keyvault-url
|
||||
rover logout
|
||||
|
||||
# login a with a user member of the caf-maintainers group
|
||||
rover login -t {{ config.platform_identity.tenant_name }}
|
||||
|
||||
rover \
|
||||
{% if keyvaults is defined and config.platform_identity.azuread_identity_mode != "logged_in_user" %}
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_management.vault_uri }} \
|
||||
{% endif %}
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
{% if platform_subscriptions_details is defined %}
|
||||
-target_subscription {{ platform_subscriptions_details.management.subscription_id }} \
|
||||
{% else %}
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
{% endif %}
|
||||
-tfstate {{ config.tfstates.platform.management.tfstate }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-p ${TF_DATA_DIR}/{{ config.tfstates.platform.management.tfstate }}.tfplan \
|
||||
-a plan
|
||||
|
||||
```
|
||||
|
||||
|
||||
# Next steps
|
||||
|
||||
When you have successfully deployed the management landing zone, you can move to the next step:
|
||||
|
||||
{% if config.platform_core_setup.enterprise_scale.enable %}
|
||||
[Deploy Enterprise Scale](../../level1/eslz/readme.md)
|
||||
{% else %}
|
||||
[Deploy Connectivity](../../level2/connectivity/readme.md)
|
||||
{% endif %}
|
|
@ -0,0 +1,88 @@
|
|||
- name: "[{{ level }}-{{ base_folder }}] Clean-up directory"
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: absent
|
||||
when: config.configuration_folders.platform.cleanup_destination | bool
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Creates directory"
|
||||
register: level1_subscriptions
|
||||
file:
|
||||
path: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}"
|
||||
state: directory
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] generate configuration files."
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }}/{{ item | basename | regex_replace('.j2$', '') }}"
|
||||
force: yes
|
||||
with_fileglob:
|
||||
- "{{ level }}/{{ base_folder }}/*.tfvars.j2"
|
||||
- "{{ level }}/{{ base_folder }}/*.md"
|
||||
|
||||
# Create the subscriptions
|
||||
- name: "[{{ level }}-{{ base_folder }}] Create subscriptions."
|
||||
when: deploy_subscriptions | bool
|
||||
shell: |
|
||||
/tf/rover/rover.sh \
|
||||
--impersonate-sp-from-keyvault-url {{ keyvaults.cred_subscription_creation_platform.vault_uri }} \
|
||||
-lz /tf/caf/landingzones/caf_solution \
|
||||
-var-folder {{ config.configuration_folders.platform.destination_base_path }}/{{ config.configuration_folders.platform.destination_relative_path }}/{{ level }}/{{ base_folder }} \
|
||||
-tfstate_subscription_id {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-target_subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
-tfstate {{ config.tfstates.platform.platform_subscriptions.tfstate }} \
|
||||
-log-severity {{ config.gitops.rover_log_error }} \
|
||||
-env {{ config.caf_terraform.launchpad.caf_environment }} \
|
||||
-level {{ level }} \
|
||||
-a apply
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get latest cache folder"
|
||||
set_fact:
|
||||
job_cache_base_path: "/home/vscode/.terraform.cache"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get tfstate details"
|
||||
register: subscription_tfstate_file_name
|
||||
shell: |
|
||||
az storage account list \
|
||||
--subscription {{ config.caf_terraform.launchpad.subscription_id }} \
|
||||
--query "[?tags.caf_tfstate=='{{ config.tfstates.platform.platform_subscriptions.level }}' && tags.caf_environment=='{{ config.caf_terraform.launchpad.caf_environment }}'].{name:name}[0]" -o json | jq -r .name
|
||||
|
||||
- debug:
|
||||
msg: "{{ subscription_tfstate_file_name.stdout }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Download tfstate details"
|
||||
register: platform_subscriptions_tfstate_exists
|
||||
ignore_errors: true
|
||||
shell: |
|
||||
az storage blob download \
|
||||
--name "{{ config.tfstates.platform.platform_subscriptions.tfstate }}" \
|
||||
--account-name "{{ subscription_tfstate_file_name.stdout }}" \
|
||||
--container-name "tfstate" \
|
||||
--auth-mode "login" \
|
||||
--file "{{ job_cache_base_path }}/{{ config.tfstates.platform.platform_subscriptions.tfstate }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get platform_subscriptions details"
|
||||
shell: "cat {{ job_cache_base_path }}/{{ config.tfstates.platform.platform_subscriptions.tfstate }}"
|
||||
register: platform_subscriptions
|
||||
when: platform_subscriptions_tfstate_exists.rc == 0
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get platform_subscriptions json data"
|
||||
when: platform_subscriptions_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
platform_sub_jsondata: "{{ platform_subscriptions.stdout | from_json }}"
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] Get subscriptions list"
|
||||
when: platform_subscriptions_tfstate_exists.rc == 0
|
||||
set_fact:
|
||||
platform_subscriptions_details: "{{ platform_sub_jsondata | json_query(path) }}"
|
||||
vars:
|
||||
path: 'outputs.objects.value.{{ config.tfstates.platform.platform_subscriptions.lz_key_name }}.subscriptions'
|
||||
|
||||
- name: "[{{ level }}-{{ base_folder }}] cleanup"
|
||||
when: platform_subscriptions_tfstate_exists.rc == 0
|
||||
file:
|
||||
path: "{{ job_cache_base_path }}/{{ config.tfstates.platform.platform_subscriptions.tfstate }}"
|
||||
state: absent
|
||||
|
||||
- debug:
|
||||
msg: "Platform subscriptions - {{ platform_subscriptions_details }}"
|
||||
when: platform_subscriptions_tfstate_exists.rc == 0
|
|
@ -0,0 +1,12 @@
|
|||
landingzone = {
|
||||
backend_type = "azurerm"
|
||||
global_settings_key = "{{ config.tfstates.platform.launchpad.lz_key_name }}"
|
||||
level = "{{ config.tfstates.platform.platform_subscriptions.level }}"
|
||||
key = "{{ config.tfstates.platform.platform_subscriptions.lz_key_name }}"
|
||||
tfstates = {
|
||||
{{ config.tfstates.platform.launchpad.lz_key_name }} = {
|
||||
level = "lower"
|
||||
tfstate = "{{ config.tfstates.platform.launchpad.tfstate }}"
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче