From f451f8bcc840ef1c4583d74b55d064b7206aa82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Falconnier?= Date: Mon, 31 Jul 2023 18:36:38 +0200 Subject: [PATCH] Add FileVaultConfig resources to Terraform export --- tests/mdm/test_setup_index.py | 21 +++++++++++++--- tests/mdm/test_terraform.py | 43 ++++++++++++++++++++++++++++++-- zentral/contrib/mdm/terraform.py | 30 ++++++++++++++++++---- 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/tests/mdm/test_setup_index.py b/tests/mdm/test_setup_index.py index 93514c5d50..fd77636fda 100644 --- a/tests/mdm/test_setup_index.py +++ b/tests/mdm/test_setup_index.py @@ -8,7 +8,7 @@ from django.urls import reverse from django.utils.crypto import get_random_string from accounts.models import User -from .utils import force_artifact, force_blueprint, force_blueprint_artifact +from .utils import force_artifact, force_blueprint, force_blueprint_artifact, force_filevault_config @override_settings(STATICFILES_STORAGE='django.contrib.staticfiles.storage.StaticFilesStorage') @@ -81,7 +81,9 @@ def test_terraform_export_permission_denied(self): def test_terraform_export(self): self._login("mdm.view_blueprint") - blueprint = force_blueprint() + fv_config1 = force_filevault_config() + fv_config2 = force_filevault_config() + blueprint = force_blueprint(filevault_config=fv_config1) required_artifact, (required_profile_av,) = force_artifact() rprofile = required_profile_av.profile rprofile_filename = f"{required_artifact.name.lower()}_{rprofile.pk}_v1.mobileconfig" @@ -92,11 +94,24 @@ def test_terraform_export(self): response = self.client.get(reverse("mdm:terraform_export")) self.assertEqual(response.status_code, 200) with zipfile.ZipFile(io.BytesIO(response.content), mode="r") as zf: + with zf.open("mdm_filevault_configs.tf") as fctf: + self.assertEqual( + fctf.read().decode("utf-8"), + f'resource "zentral_mdm_filevault_config" "filevaultconfig{fv_config1.pk}" {{\n' + f' name = "{fv_config1.name}"\n' + f' escrow_location_display_name = "{fv_config1.escrow_location_display_name}"\n' + '}\n\n' + f'resource "zentral_mdm_filevault_config" "filevaultconfig{fv_config2.pk}" {{\n' + f' name = "{fv_config2.name}"\n' + f' escrow_location_display_name = "{fv_config2.escrow_location_display_name}"\n' + '}\n\n' + ) with zf.open("mdm_blueprints.tf") as btf: self.assertEqual( btf.read().decode("utf-8"), f'resource "zentral_mdm_blueprint" "blueprint{blueprint.pk}" {{\n' - f' name = "{blueprint.name}"\n' + f' name = "{blueprint.name}"\n' + f' filevault_config_id = zentral_mdm_filevault_config.filevaultconfig{fv_config1.pk}.id\n' '}\n\n' f'resource "zentral_mdm_blueprint_artifact" "blueprintartifact{blueprint_artifact.pk}" {{\n' f' blueprint_id = zentral_mdm_blueprint.blueprint{blueprint.pk}.id\n' diff --git a/tests/mdm/test_terraform.py b/tests/mdm/test_terraform.py index 39ab296545..165fe19325 100644 --- a/tests/mdm/test_terraform.py +++ b/tests/mdm/test_terraform.py @@ -4,8 +4,9 @@ from zentral.contrib.mdm.models import Artifact, Blueprint from zentral.contrib.mdm.terraform import (ArtifactResource, BlueprintResource, BlueprintArtifactResource, + FileVaultConfigResource, ProfileResource) -from .utils import force_artifact, force_blueprint, force_blueprint_artifact +from .utils import force_artifact, force_blueprint, force_blueprint_artifact, force_filevault_config class MDMTerraformTestCase(TestCase): @@ -98,6 +99,42 @@ def test_profile_resource_full(self): '}' ) + # FileVault config + + def test_filevault_config_resource_defaults(self): + filevault_config = force_filevault_config() + resource = FileVaultConfigResource(filevault_config) + self.assertEqual( + resource.to_representation(), + f'resource "zentral_mdm_filevault_config" "filevaultconfig{filevault_config.pk}" {{\n' + f' name = "{filevault_config.name}"\n' + f' escrow_location_display_name = "{filevault_config.escrow_location_display_name}"\n' + '}' + ) + + def test_filevault_config_resource_full(self): + filevault_config = force_filevault_config() + filevault_config.at_login_only = True + filevault_config.bypass_attempts = 1 + filevault_config.show_recovery_key = True + filevault_config.destroy_key_on_standby = True + filevault_config.prk_rotation_interval_days = 90 + filevault_config.save() + + resource = FileVaultConfigResource(filevault_config) + self.assertEqual( + resource.to_representation(), + f'resource "zentral_mdm_filevault_config" "filevaultconfig{filevault_config.pk}" {{\n' + f' name = "{filevault_config.name}"\n' + f' escrow_location_display_name = "{filevault_config.escrow_location_display_name}"\n' + ' at_login_only = true\n' + ' bypass_attempts = 1\n' + ' show_recovery_key = true\n' + ' destroy_key_on_standby = true\n' + ' prk_rotation_interval_days = 90\n' + '}' + ) + # blueprint def test_blueprint_resource_defaults(self): @@ -111,7 +148,8 @@ def test_blueprint_resource_defaults(self): ) def test_blueprint_resource_full(self): - blueprint = force_blueprint() + filevault_config = force_filevault_config() + blueprint = force_blueprint(filevault_config=filevault_config) blueprint.inventory_interval = 77777 blueprint.collect_apps = Blueprint.InventoryItemCollectionOption.MANAGED_ONLY blueprint.collect_certificates = Blueprint.InventoryItemCollectionOption.ALL @@ -126,6 +164,7 @@ def test_blueprint_resource_full(self): ' collect_apps = "MANAGED_ONLY"\n' ' collect_certificates = "ALL"\n' ' collect_profiles = "ALL"\n' + f' filevault_config_id = zentral_mdm_filevault_config.filevaultconfig{filevault_config.pk}.id\n' '}' ) diff --git a/zentral/contrib/mdm/terraform.py b/zentral/contrib/mdm/terraform.py index 331487e261..cc9bd89b40 100644 --- a/zentral/contrib/mdm/terraform.py +++ b/zentral/contrib/mdm/terraform.py @@ -1,4 +1,4 @@ -from .models import Artifact, Blueprint +from .models import Artifact, Blueprint, FileVaultConfig from zentral.contrib.inventory.terraform import TagResource from zentral.utils.terraform import BoolAttr, FileBase64Attr, IntAttr, MapAttr, RefAttr, Resource, StringAttr @@ -18,6 +18,19 @@ class ArtifactResource(Resource): requires = RefAttr("zentral.contrib.mdm.terraform.ArtifactResource", many=True, default=list) +class FileVaultConfigResource(Resource): + tf_type = "zentral_mdm_filevault_config" + tf_grouping_key = "mdm_filevault_configs" + + name = StringAttr(required=True) + escrow_location_display_name = StringAttr(required=True) + at_login_only = BoolAttr(default=False) + bypass_attempts = IntAttr(default=-1) + show_recovery_key = BoolAttr(default=False) + destroy_key_on_standby = BoolAttr(default=False) + prk_rotation_interval_days = IntAttr(default=0) + + class BlueprintResource(Resource): tf_type = "zentral_mdm_blueprint" tf_grouping_key = "mdm_blueprints" @@ -30,6 +43,7 @@ class BlueprintResource(Resource): source="get_collect_certificates_display") collect_profiles = StringAttr(default=Blueprint.InventoryItemCollectionOption.NO.name, source="get_collect_profiles_display") + filevault_config_id = RefAttr(FileVaultConfigResource) # TODO: deduplicate Resource @@ -92,13 +106,19 @@ def get_pk(self): def iter_resources(): - for blueprint in Blueprint.objects.prefetch_related("blueprintartifact_set__artifact", - "blueprintartifact_set__blueprint", - "blueprintartifact_set__excluded_tags", - "blueprintartifact_set__item_tags__tag").all(): + for blueprint in (Blueprint.objects + .select_related("filevault_config") + .prefetch_related("blueprintartifact_set__artifact", + "blueprintartifact_set__blueprint", + "blueprintartifact_set__excluded_tags", + "blueprintartifact_set__item_tags__tag").all()): yield BlueprintResource(blueprint) + if blueprint.filevault_config: + yield FileVaultConfigResource(blueprint.filevault_config) for blueprint_artifact in blueprint.blueprintartifact_set.all(): yield BlueprintArtifactResource(blueprint_artifact) + for filevault_config in FileVaultConfig.objects.all(): + yield FileVaultConfigResource(filevault_config) for artifact in Artifact.objects.prefetch_related("requires").filter(type=Artifact.Type.PROFILE): yield ArtifactResource(artifact) for artifact_version in artifact.artifactversion_set.select_related("profile").order_by("-version"):