I am creating a key vault through an Azure Blueprint: it gets created with no problem.
The thing is that, in order to access the Key Vault (Listing it, putting or getting values) Access Policies must be configured.
With ARM templates, I could insert a section like :
"accessPolicies": [
{
"tenantId": "22222222-3333-4444-aaaa-eeeeeeeeeeee",
"objectId": "77777777-6666-4444-8888-111111111111",
"permissions": {
"keys": [
"Get",
...
"Restore"
],
"secrets": [
"Get",
...
"Restore"
],
"certificates": []
}
},
but I'd need to have a TenantId and an ObjectId to hardcode, or to get as parameter, which is not the right way to do it.
Unfortunately I could not find a way to assign these access policies to the Key Vault, without which the key vault itself just can't be used, unless making those settings manual (and deleting them each time the blueprint is upgraded).
Is there a guideline or a best practice to do this in the proper way ?
The tenantId you can get dynamically using "[subscription().tenantId]". See official documentation.
Regarding the objectId, using a parameter is usually the right way as stated in this answer. ObjectIDs are not on the same layer as ARM components and therefore there aren't real way to get those dynamically using ARM.
Starting from the answer from #jul_DW, I realized that ARM could not set in an easy way users, so I should have used to something in the Blueprint.
And infact, one of the key features for Blueprint is Role Assignment.
To use this approach we need to enable the RBAC for the Key Vault, but that is done easily in the ARM template itself:
...
"type": "Microsoft.KeyVault/vaults",
"properties": {
...
"enableRbacAuthorization": true,
...
}
Once the RBAC is enabled, the ARM template should stay away from assigning permissions, and the Role Assignment feature from Blueprints should be used.
In my case, I assigned a Key Vault Administrator role to the needed user group, that can be indicated as a parameter. In this way the ARM template is kept as simple as possible, and at the same time we have a great flexibility in assigning roles to different users in the various environments.
Related
We are trying to replace our existing PSPs in kubernetes with OPA policies using Gatekeeper. I'm using the default templates provided by Gatekeeper https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/pod-security-policy and defined corresponding constraints.
However, I can't figure out how I can apply a policy to a specific ServiceAccount.
For eg. how to define allow-privilege-escalation policy only to a ServiceAccount named awsnode?
In PSPs I create a Role/ClusterRole for required podsecuritypolicies and create a RoleBinding to allow awsnode ServiceAccount to use required PSP. I'm struggling to understand how to achieve the same using Gatekeeper OPA policies?
Thank you.
Apparently PSPs and Gatekeeper OPA policies are designed to achieve pod security at different levels. Here is the response from AWS support on the above question.
Gatekeeper constraint templates (and the corresponding constraint CRDs defined from the templates) apply to a larger scope of Kubernetes resources than just pods. Gatekeeper extends additional functionality that RBAC cannot provide at this stage.
Gatekeeper itself cannot be managed by RBAC (by means of using verbs to restrict access to Gatekeeper constraints), because no RBAC resource keyword exists for Gatekeeper policy constraints (at least, at the time of writing this).
PodSecurity Admission Controller might be an option for someone looking for a replacement for PSPs which needs to be controlled by RBAC if the cluster is on 1.22 version or above.
I think a possible solution to applying an OPA Gatekeeper policy (a ConstraintTemplate) to a specific ServiceAccount, is to make the OPA/Rego policy code reflect that filter / selection logic. Since you said you're using pre-existing policies from the gatekeeper-library, maybe changing the policy code isn't an option for you. But if changing it is an option, I think your OPA/Rego policy can take into account the pod's serviceAccount field. Keep in mind with OPA Gatekeeper, the input to the Rego policy code is the entire admission request, including the spec of the pod (assuming it's pod creations that you're trying to check).
So part of the input to the Rego policy code might be like
"spec": {
"volumes": [... ],
"containers": [
{
"name": "apache",
"image": "docker.io/apache:latest",
"ports": [... ],
"env": [... ],
"resources": {},
"volumeMounts": [... ],
"imagePullPolicy": "IfNotPresent",
"securityContext": {... }
}
],
"restartPolicy": "Always",
"terminationGracePeriodSeconds": 30,
"dnsPolicy": "ClusterFirst",
"serviceAccountName": "apache-service-account",
"serviceAccount": "apache-service-account",
So gatekeeper-library's allow-privilege-escalation references input.review.object.spec.containers and finds an array of containers like "apache". Similarly, you could modify the policy code to reference input.review.object.spec.serviceAccount and find "apache-service-account". From there, it's a matter of using that information to make sure the rule "violation" only matches if the service account is one you want to apply to.
Beyond that, it's possible to then take the expected service account name and make it a ConstraintTemplate parameter, to make your new policy more flexible/useable.
Hope this helps!
Its just a concept im having trouble understanding with the wildcard * and what that means, so here we have two roles Owner and contributor.
"Name": "Contributor",
"Id": "b24988ac-6180-42a0-ab88-20f7382dd24c",
"IsCustom": false,
"Description": "Lets you manage everything except access to resources.",
"Actions": ["*"],
"NotActions": [
"Microsoft.Authorization/*/Delete",
"Microsoft.Authorization/*/Write",
"Microsoft.Authorization/elevateAccess/Action'],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [],
"/"
Name : Owner
Id : 8e3af657-a8ff-443c-a75c-2fe8c4bcb635
IsCustom : False
Description : Grants full access to manage all resources, including the ability to assign roles in Azure RBAC.
Actions : {*}
NotActions : {}
DataActions : {}
NotDataActions : {}
AssignableScopes : {/}
So my hang up is use of the astrisk, i know * under Owner means everything but with contributor, why is it used under the NotActions permissions? Why is it "Microsoft.Authorization/*/Delete" instead of Microsoft.Authorization/Delete". The permission in question stops the contributor from deleting users. So i know how these roles and permissions work, im just really struggling with the syntax. I have read the documentation on microsoft learn but there is something i clearly dont understand about the *. Does anyone with any knowledge know of a way of explaining this to help clear it up or maybe someone could point me to some better documentation? Any help would be greatly appreciated.
Why is it "Microsoft.Authorization/*/Delete" instead of
Microsoft.Authorization/Delete".
To understand this, please see this link especially Operations format section.
Essentially each operation is specified in {Company}.{ProviderName}/{resourceType}/{action} format.
So when you specify the operation as Microsoft.Authorization/*/Delete, you're essentially allowing delete operation on all the resources under Microsoft.Authorization resource provider.
This format also enables you to specify actions granularly at each resource level under a resource provider.
I was asked by Azure Support to post this question, just to see if anyone had a useful opinion.
I am stepping through MS Azure training courses. I created the usual free account to go through these. I've gone through a few dozen of them, and am now at this one:
https://learn.microsoft.com/en-us/learn/modules/secure-and-isolate-with-nsg-and-service-endpoints/3-exercise-network-security-groups?source=learn
This attempts to use the Azure PowerShell service. I had some trouble getting to the PowerShell page. It appears that if I'm not already logged into the portal, it goes into a semi-infinite loop, trying to get to the shell page, then trying to login, then the shell page, and finally it gives up and says "We couldn't sign you in. Please try again.".
However, I was able to work around this. If in a separate tab, I log into the Azure Portal, and then go back and follow the link to Azure Cloud Shell, it passes the login gate and sends me to the page where I choose Bash or PowerShell. The course specifies using Bash. When I select that, it then asks me to create a Storage object. When I confirm that, it gives me the following error (subscription id elided):
{
"error": {
"code": "RequestDisallowedByPolicy",
"target": "cs733f82532facdx4f04x95b",
"message": "Resource 'cs733f82532facdx4f04x95b' was disallowed by policy. Policy identifiers: '[{\"policyAssignment\":{\"name\":\"Enforce tag on resource\",\"id\":\"/subscriptions/xxxxx/providers/Microsoft.Authorization/policyAssignments/740514d625684aad84ef8ca0\"},\"policyDefinition\":{\"name\":\"Enforce tag on resource\",\"id\":\"/subscriptions/xxxxx/providers/Microsoft.Authorization/policyDefinitions/be3862a6-ca1e-40b0-a024-0c0c7d1e8b3e\"}}]'.",
"additionalInfo": [
{
"type": "PolicyViolation",
"info": {
"policyDefinitionDisplayName": "Enforce tag on resource",
"evaluationDetails": {
"evaluatedExpressions": [
{
"result": "True",
"expressionKind": "Field",
"expression": "tags[Department]",
"path": "tags[Department]",
"targetValue": "false",
"operator": "Exists"
}
]
},
"policyDefinitionId": "/subscriptions/xxxxx/providers/Microsoft.Authorization/policyDefinitions/be3862a6-ca1e-40b0-a024-0c0c7d1e8b3e",
"policyDefinitionName": "be3862a6-ca1e-40b0-a024-0c0c7d1e8b3e",
"policyDefinitionEffect": "deny",
"policyAssignmentId": "/subscriptions/xxxxx/providers/Microsoft.Authorization/policyAssignments/740514d625684aad84ef8ca0",
"policyAssignmentName": "740514d625684aad84ef8ca0",
"policyAssignmentDisplayName": "Enforce tag on resource",
"policyAssignmentScope": "/subscriptions/xxxxx",
"policyAssignmentParameters": {
"tagName": {
"value": "Department"
}
}
}
}
]
}
}
I think the simple conclusion from this is that my free account doesn't have enough rights to do what is needed here. The documentation I've read seems to imply that I have to get additional rights on the account in order to do this. However, I'm just using a free account that I created to go through the Azure training courses. It doesn't really make sense to ask me to do this. I've seen other Azure courses create a temporary sandbox supposedly because they have particular objects pre-created in the sandbox, but I'm also thinking that the sandbox has particular permissions that are not available in the free account. It seems to me that the only reasonable fix for this problem is for that course to be refactored to use a temporary sandbox with the correct permissions.
I'm just looking for any opinions on this, and confirmations that this is what should be done.
It doesn't look like you are creating resource, cloudshell storage, on your free subscription. Except if you added to a Work/Corporate tenant.
From the information you provide, subscription you are trying to use has a policy to enforce tags Department, mean any resource created should have a tag with Department information.
We have 4 different b2c accounts to reflect our different stages.(dev,test,preprod,prod). We deploy the custom policies with jenkins and they are be the same (except for the tenant). In dev and preprod I get for the jwk
{
"keys": [
{"kid":"cryDHrls_bD7W0G0PEd-4k61TsW-aQmprRc4hxVwLEo","use":"sig","kty":"RSA","e":"AQAB","n":"uXyfO_YvhkxIhk3k3cFmvigl9tcewAaohABpukYsUceakNOzGHSvnT0uAX7-0k_xa5PKA7pgskgQYeN70iUw4BIlbaBISpJKZpiY0wv3H23EbrTt6aUV7rvBYH2UoJ2LoBhsQaqM3Wer7wD8TjPT11azPUSOyuS7Ju5NZeG723kIxNFFb0H4_eHsHeFkxktxXxmcVMDDlWIpq85PCJepdf-KtXbWLl3QfLa5CG6rTd3R6p53CDX0ktg1weNqlcg3W05D_zBJ9_QLP-9tJKqQIoN4L-5aAlIvzcM2rQpjljHqxg11c7p4ecqqg8IBoh7Ob5BgE1lPpKdcNDdpW6g2vQ"}
]
and
{
"keys": [
{"kid":"whWP-xfUz5r-B2hkKRuttLaF17jNQWPjKvvt0t6RnXs","use":"sig","kty":"RSA","e":"AQAB","n":"l3XZpxOy3Aj5OAssunKXMB2RMLcZqG5Ilch5SibtHvUF4Lg-OAf-8HImVwcVljPRXXcRe3yb9AWMon60X3TESkpRFwM-JZv70r0pZgaI-UPRjBo8bI_T9JlbNc9-Eyh68aGX09go7prlshQCdt4QRbueNCMRtogU0xcKUh5JnGWgDlqptCFgTQETunPBdaqASEMzW4_E7iPhcK017bg2Y_kc52AOQNlx27gjWv9G1ql7tmtUGdV0FfjBdBA4wxi6foHmk_7Akj99DdxI7B0QTxbUh1ZSeOYBVPyFSrGir4oGzK4Tn50D9R_W4LYJRqdZIB0zUrAwSyU3uLWg4b9pDQ"}
]
}
respectively. But on our test account I get
{
"keys": [
{"kid":"Gwsav9XG6fIaFHmzxMUZ0AvF_VpKCOsI_8qmQ53-uO4","use":"sig","kty":"oct"}
]
}
I didn't find any option to set/influence this and our java lib (auth0) for checking jwt doesn't work with that kind of jwk.
You may be connecting to the wrong endpoint to get the key.
Normally you should first connect to the .well-know endpoint for your tenant and policy, e.g. https://login.microsoftonline.com/tfp/tenant_name.onmicrosoft.com/policy_name/v2.0/.well-known/openid-configuration. From the response you then retrieve the jwks_uri, which is something like https://login.microsoftonline.com/te/tenant_name.onmicrosoft.com/policy_name/discovery/v2.0/keys. Note that this is different than the endpoint you gave us in your comments, so this may be your issue. The correct key endpoint includes the "te" in the URL, and the policy is part of the URL, not passed in the query string.
I created a new tenant, but actually found the answer to my own question. When you create the TokenSigningKeyContainer key, make sure you choose RSA.
I'm trying to derive the Registration Key and Url of my Azure Automation DSC account inside the ARM template at runtime. I've tried using the same syntax as you would for a storage account, ie.
listKeys(resourceId('Microsoft.Storage/storageAccounts', 'StorageAccountName'), '2015-05-01-preview').key1)
by doing this:
listKeys(resourceId('Microsoft.Automation/automationAccounts', 'AutomationAccountName'), '2015-05-01-preview').key1)
but no luck (it appears the function simply returns null). This would naturally make provisioning an automation account and and a VM and wiring up the VM to the automation account in the same template easy as pie. Has anyone successfully got something similar to work?
As per this GitHub Ticket, this is still under development.
https://github.com/azureautomation/automation-packs/issues/7
With version 2015-10-31 of the Azure Automation API, the following seems to work.
Getting the registration URL:
reference(resourceId('Microsoft.Automation/automationAccounts/', 'AutomationAccountName'), '2015-10-31').RegistrationUrl
Getting the Primary key:
listKeys(resourceId('Microsoft.Automation/automationAccounts/', 'AutomationAccountName'), '2015-10-31').keys[0].value
Getting the Secondary key:
listKeys(resourceId('Microsoft.Automation/automationAccounts/', 'AutomationAccountName'), '2015-10-31').keys[1].value
For reference, the object returned from the listKeys() template function for an Automation account resource looks like this (can easily be found by adding an output value using listKeys() to the outputs section of an ARM template):
{
"keys": [
{
"KeyName": "Primary",
"Permissions": "Full",
"Value": "VALUE OF PRIMARY KEY"
},
{
"KeyName": "Secondary",
"Permissions": "Full",
"Value": "VALUE OF SECONDARY KEY"
}
]
}