Deny assigning Contributor or Owner to Service Principal

Greetings,

I’m working on a policy to deny any attempt (via TF) to assign either Contributor or Owner privileges to a Service Principal. I can see how to deny assigning Contributor or Owner via azurerm_role_assignment but don’t see how to limit that to just Service Principals. Is it possible to single out SPs?

Is it possible to use the principal_type attribute somehow?

Hard to tell without seeing the mock data for the plan but I think you need to use the principal_id as I am not sure if you will know the principal_type attribute at the time that the plan is generated.

If you share mocks or config it will be easier to say for sure


planned_values = {
        "outputs": {},
        "resources": {
                "azurerm_role_assignment.example": {
                        "address":        "azurerm_role_assignment.example",
                        "depends_on":     [],
                        "deposed_key":    "",
                        "index":          null,
                        "mode":           "managed",
                        "module_address": "",
                        "name":           "example",
                        "provider_name":  "registry.terraform.io/hashicorp/azurerm",
                        "tainted":        false,
                        "type":           "azurerm_role_assignment",
                        "values": {
                                "principal_id":         <removed>,
                                "role_definition_name": "Contributor",
                                "scope":                <removed>,
                                "timeouts":             null,
                        },
                },
        },
}

variables = {}

resource_changes = {
        "azurerm_role_assignment.example": {
                "address": "azurerm_role_assignment.example",
                "change": {
                        "actions": [
                                "create",
                        ],
                        "after": {
                                "principal_id":         <removed>,
                                "role_definition_name": "Contributor",
                                "scope":                <removed>,
                                "timeouts":             null,
                        },
                        "after_unknown": {
                                "id":                               true,
                                "name":                             true,
                                "principal_type":                   true,
                                "role_definition_id":               true,
                                "skip_service_principal_aad_check": true,
                        },
                        "before": null,
                },
                "deposed":        "",
                "index":          null,
                "mode":           "managed",
                "module_address": "",
                "name":           "example",
                "provider_name":  "registry.terraform.io/hashicorp/azurerm",
                "type":           "azurerm_role_assignment",
        },
}

output_changes = {}

raw = {
        "configuration": {
                "provider_config": {
                        "azurerm": {
                                "expressions": {
                                        "features": [
                                                {},
                                        ],
                                },
                                "name":               "azurerm",
                                "version_constraint": ">=2.25.0",
                        },
                },
                "root_module": {
                        "resources": [
                                {
                                        "address": "azurerm_role_assignment.example",
                                        "expressions": {
                                                "principal_id": {
                                                        "constant_value": <removed>,
                                                },
                                                "role_definition_name": {
                                                        "constant_value": "Contributor",
                                                },
                                                "scope": {
                                                        "constant_value": <removed>,
                                                },
                                        },
                                        "mode":                "managed",
                                        "name":                "example",
                                        "provider_config_key": "azurerm",
                                        "schema_version":      0,
                                        "type":                "azurerm_role_assignment",
                                },
                        ],
                },
        },
        "format_version": "0.1",
        "planned_values": {
                "root_module": {
                        "resources": [
                                {
                                        "address":        "azurerm_role_assignment.example",
                                        "mode":           "managed",
                                        "name":           "example",
                                        "provider_name":  "registry.terraform.io/hashicorp/azurerm",
                                        "schema_version": 0,
                                        "type":           "azurerm_role_assignment",
                                        "values": {
                                                "principal_id":         <removed>,
                                                "role_definition_name": "Contributor",
                                                "scope":                <removed>,
                                                "timeouts":             null,
                                        },
                                },
                        ],
                },
        },
        "resource_changes": [
                {
                        "address": "azurerm_role_assignment.example",
                        "change": {
                                "actions": [
                                        "create",
                                ],
                                "after": {
                                        "principal_id":         <removed>,
                                        "role_definition_name": "Contributor",
                                        "scope":                <removed>,
                                        "timeouts":             null,
                                },
                                "after_unknown": {
                                        "id":                               true,
                                        "name":                             true,
                                        "principal_type":                   true,
                                        "role_definition_id":               true,
                                        "skip_service_principal_aad_check": true,
                                },
                                "before": null,
                        },
                        "mode":          "managed",
                        "name":          "example",
                        "provider_name": "registry.terraform.io/hashicorp/azurerm",
                        "type":          "azurerm_role_assignment",
                },
        ],
        "terraform_version": "0.13.4",
}

I believe that since the type is an output, it won’t be known until after the apply - which doesn’t help me. If that is the case, is there another way to filter on the type?

That is correct.

Having reviewed your use case a bit more, I think you should seriously consider short-lived service principals (SPN) using Vault. I don’t know a great deal about your environment setup but managing service principals at scale is really difficult and Vault allows you to dynamically provision a SPN with the correct roles assigned on the fly.

You can read more here: