Does WAF need to be included as part of Application Gateway creation? - powershell

As part of BCP/Disaster Recover planning, we want to simulate a restoration scenario of the application gateway template we have in bitbucket.
I have the json template as well as parameters file in the repository, but I also see a WAF rule template files for the gateway.
So basically there are 4 files....but the New-AzResourceGroupDeployment only takes in the main template file (-TemplateUri) as well as parameters file (-TemplateParameterUri). so how would i be able to specify the WAF templates as part of the gateway creation?
I do see references to the WAF rules in the main gateway template file but is that enough?
sku information:
"properties": {
"sku": {
"name": "WAF_v2",
"tier": "WAF_v2",
"capacity": 1

You can add WAF policies while creating the WAF v2 Gateway by just adding the below in the Template file in the same way it has been done in this Microsoft Documentation and providing the values as per your requirement :
{
"type": "Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies",
"apiVersion": "2020-06-01",
"name": "[variables('AGWafPol01')]",
"location": "[parameters('location')]",
"properties": {
"customRules": [
{
"name": "CustRule01",
"priority": 100,
"ruleType": "MatchRule",
"action": "Block",
"matchConditions": [
{
"matchVariables": [
{
"variableName": "RemoteAddr"
}
],
"operator": "IPMatch",
"negationConditon": true,
"matchValues": [
"10.10.10.0/24"
]
}
]
}
],
"policySettings": {
"requestBodyCheck": true,
"maxRequestBodySizeInKb": 128,
"fileUploadLimitInMb": 100,
"state": "Enabled",
"mode": "Prevention"
},
"managedRules": {
"managedRuleSets": [
{
"ruleSetType": "OWASP",
"ruleSetVersion": "3.1"
}
]
}
}
},

Related

How to create idempotent, re-deployable ARM templates that utilize Key Vault? Circular dependencies present issues

I'm trying to incorporate some additional security features on my resources such as encryption using customer managed keys. For the Service Bus, this requires the Service Bus to have a managed identity created and granted access to the Key Vault. However, the managed identity is not known until after the Service Bus exists.
In my ARM template, I need to initialize the Service Bus without encryption in order to get a managed identity, grant that identity access to key vault, then update the Service Bus with encryption. However, this deployment process is not repeatable. On subsequent re-deployments, it will fail because encryption cannot be removed from a Service Bus once it is granted. Even if it did work, I would be performing unnecessary steps to remove encryption and add it back on every deployment. It seems that an IAC template that describes the expected final state of the resource cannot be used to both maintain and bootstrap a new environment.
The same problem exists for API Management, I want to add custom domains but they require Key Vault access. It means I can't re-deploy my ARM template without removing the custom domains when the init step gets repeated (or keep a separate set of templates for 'initialization' vs the 'real deployment'.
Is there a better solution for this? I looked into user assigned identities which seems like it could solve the problem, but they aren't supported in ARM templates. I checked if there is a way to make the 'init' step conditional by checking if the resource already exists, and this is also not supported via ARM template.
If you want to maintain a single ARM template, you can use nested deployments to define a resource then reference it again to update it.
In the following example, I create the Service Bus with a system-assigned managed identity, a Key Vault, and an RSA key. In a nested deployment within the same ARM template that depends on that key being generated, I then update the Service Bus to enable encryption. An advantage of being all in the same template is that resourceId and reference can be used with abbreviated syntax (i.e. just the resource name).
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"name": {
"type": "string",
"defaultValue": "[resourceGroup().name]"
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
},
"tenantId": {
"type": "string",
"defaultValue": "[subscription().tenantId]"
}
},
"variables": {
"kv_name": "[concat(parameters('name'), 'kv')]",
"kv_version": "2019-09-01",
"sb_name": "[concat(parameters('name'), 'sb')]",
"sb_version": "2018-01-01-preview",
"sb_keyname": "sbkey"
},
"resources": [
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "[variables('sb_version')]",
"name": "[variables('sb_name')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 1
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"zoneRedundant": false
}
},
{
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "[variables('kv_version')]",
"name": "[variables('kv_name')]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('sb_name')]"
],
"properties": {
"sku": {
"family": "A",
"name": "Standard"
},
"tenantId": "[parameters('tenantId')]",
"accessPolicies": [
{
"tenantId": "[reference(variables('sb_name'), variables('sb_version'), 'Full').identity.tenantId]",
"objectId": "[reference(variables('sb_name'), variables('sb_version'), 'Full').identity.principalId]",
"permissions": {
"keys": [
"get",
"wrapKey",
"unwrapKey"
]
}
}
],
// Both must be enabled to encrypt Service Bus at rest.
"enableSoftDelete": true,
"enablePurgeProtection": true
}
},
{
"type": "Microsoft.KeyVault/vaults/keys",
"apiVersion": "[variables('kv_version')]",
"name": "[concat(variables('kv_name'), '/', variables('sb_keyname'))]",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('kv_name')]"
],
"properties": {
"kty": "RSA",
"keySize": 2048,
"keyOps": [
"wrapKey",
"unwrapKey"
],
"attributes": {
"enabled": true
}
}
},
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2020-10-01",
"name": "sb_deployment",
"dependsOn": [
"[resourceId('Microsoft.KeyVault/vaults/keys', variables('kv_name'), variables('sb_keyname'))]"
],
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"type": "Microsoft.ServiceBus/namespaces",
"apiVersion": "[variables('sb_version')]",
"name": "[variables('sb_name')]",
"location": "[parameters('location')]",
"sku": {
"name": "Premium",
"tier": "Premium",
"capacity": 1
},
"identity": {
"type": "SystemAssigned"
},
"properties": {
"zoneRedundant": false,
"encryption": {
"keySource": "Microsoft.KeyVault",
"keyVaultProperties": [
{
// Ideally should specify a specific version, but no ARM template function to get this currently.
"keyVaultUri": "[reference(variables('kv_name')).vaultUri]",
"keyName": "[variables('sb_keyname')]"
}
]
}
}
}
]
}
}
}
]
}
To deploy this using the Azure CLI:
az group create -g rg-example -l westus2
az deployment group create -g rg-example -f template.json --parameters name=example

How to add Roles in AppInsight Access control using ARM template

I am trying to add Role Assignment in AppInsight Access control using ARM template.
I am able to create AppInsight with ARM template but unable to move ahead with addition of Role Assignment in App Insight Access control . Following is my code for creation of App Insight using ARM template
"resources": [
{
"type": "Microsoft.Insights/components",
"kind": "web",
"name": "[parameters('components_AppInsightPoc_name')]",
"apiVersion": "2015-05-01",
"location": "westus2",
"scale": null,
"properties": {
"Application_Type": "web",
"Flow_Type": "Redfield",
"Request_Source": "IbizaAIExtension",
"HockeyAppId": null,
"SamplingPercentage": null
}
}
]
You can use this snippet to add RBAC roles to the resource:
{
"type": "Microsoft.Insights/components/providers/roleAssignments",
"apiVersion": "2017-05-01",
"name": "[concat(parameters('components_AppInsightPoc_name'), '/Microsoft.Authorization/', guid('something'))]",
"properties": {
"roleDefinitionId": "[concat(subscription().Id, '/providers/Microsoft.Authorization/roleDefinitions/', 'role_guid')]",
"principalId": "user_guid",
"scope": "[resourceId('Microsoft.Insights/components', parameters('components_AppInsightPoc_name'))"
}
}
you can get role guids with powershell:
Get-AzRoleDefinition
Able to add RBAC for App Insights with the following code
"resources": [
{
"type": "Microsoft.Insights/components/providers/roleAssignments",
"apiVersion": "2017-05-01",
"name": "[concat(parameters('AppInsightName'),'/Microsoft.Authorization/',guid('AppInsightName'))]",
"properties": {
"roleDefinitionId": "[variables(parameters('builtInRoleType'))]",
"principalId": "[parameters('principalId')]"
}
}
]
I posted an answer on this question: Apply Azure RBAC to resource using ARM
I have an array of Role IDs that I wanted to add as Owners at the App Insight resource, without making the users Owners at the Resource Group level. I didn't want to use the nested resource approach as I wanted to iterate over an array of objects to dynamically create the roles, so after tweaking the type, name, and scope attributes, the following resource block is what ended up working for me:
{
"comments": "Add the Application Insights resource",
"apiVersion": "2014-04-01",
"name": "[variables('appInsightsName')]",
"type": "Microsoft.Insights/components",
"location": "[resourceGroup().location]",
"properties": {
"ApplicationId": "[variables('appInsightsName')]"
}
},
{
"comments": "Add the IAM roles to the App Insights resource",
"condition": "[parameters('isProduction')]",
"type": "Microsoft.Insights/components/providers/roleAssignments",
"name": "[concat(variables('appInsightsName'),'/Microsoft.Authorization/',guid(parameters('roleAssignments')[copyIndex()].principalId))]",
"apiVersion": "2017-05-01",
"location": "[resourceGroup().location]",
"properties": {
"roleDefinitionId": "[concat(subscription().Id, '/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", // Owner Role
"principalId": "[parameters('roleAssignments')[copyIndex()].principalId]",
"scope": "[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]"
},
"copy": {
"name": "appInsightsRoleAssignments",
"count": "[length(parameters('roleAssignments'))]"
},
"dependsOn": [
"[resourceId('Microsoft.Insights/components', variables('appInsightsName'))]"
]
}
Pay close attention to the segments in the type, name, and scope properties of the Microsoft.Insights/components/providers/roleAssignments resource.

How to update an existing AWS API Gateway using CloudFormation Template

I have the following Swagger definition file that I was able to import to an existing AWS API Gateway through "Import API" option in the AWS Console. Now, I would like to do the same thing using a CloudFormation template. I would like to know if I can update an existing AWS API Gateway with the 'PATHS' through CloudFormation template. I have read the documentation in AWS, but I couldn't find any information. The AWS::ApiGateway::RestApi resource have no way of referring to an existing AWS API Gateway. The existing API Gateway was created manually from the AWS console (i.e, not created through CloudFormation template)
{
"openapi": "3.0.1",
"info": {
"title": "Common API",
"description": "defaultDescription",
"version": "0.3"
},
"servers": [
{
"url": "http://localhost:32780"
}
],
"paths": {
"/catalogs": {
"get": {
"description": "Auto generated using Swagger Inspector",
"parameters": [
{
"name": "language",
"in": "query",
"required": false,
"style": "form",
"explode": true,
"example": "en"
},
{
"name": "category",
"in": "query",
"required": false,
"style": "form",
"explode": true,
"example": "region"
},
{
"name": "subcategory",
"in": "query",
"required": false,
"style": "form",
"explode": true,
"example": "group"
}
],
"responses": {
"200": {
"description": "Auto generated using Swagger Inspector",
"content": {
"application/json;charset=UTF-8": {
"schema": {
"type": "string"
},
"examples": {}
}
}
}
},
"servers": [
{
"url": "http://localhost:32780"
}
]
},
"servers": [
{
"url": "http://localhost:32780"
}
]
}
}
}
as you have already created your API from the Console and trying to update it. Not sure whether the CFT can help but probably you can try once. As CloudFormation is capable of modulating/updating the API deployed under the same API Name or API Key.
So, you can probably note down the Name of the API you have created from the Console and try creating/deploying the API with the same name through CloudFormation.
RestAPI:
Type: AWS::Serverless::Api
Properties:
Name: !Sub "your ApiName from the console"
StageName: !Sub "dev"
DefinitionBody:
"Fn::Transform":
Name: "AWS::Include"
Parameters:
Location: !Sub "s3://${TemporaryBucket}/openapi.yaml"
Instead of calling the API from S3, the API Defition/Body can also be defined in the Cloudformation template itself for ease.

Azure Blob Storage Deployment: Stored Access Policy gets deleted

Context:
I deploy a storage account as well as one or more containers with the following ARM template with Azure DevOps respectively a Resource Deployment Task:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"storageAccountName": {
"type": "string",
"metadata": {
"description": "The name of the Azure Storage account."
}
},
"containerNames": {
"type": "array",
"metadata": {
"description": "The names of the blob containers."
}
},
"location": {
"type": "string",
"metadata": {
"description": "The location in which the Azure Storage resources should be deployed."
}
}
},
"resources": [
{
"name": "[parameters('storageAccountName')]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2018-07-01",
"location": "[parameters('location')]",
"kind": "StorageV2",
"sku": {
"name": "Standard_LRS",
"tier": "Standard"
},
"properties": {
"accessTier": "Hot"
}
},
{
"name": "[concat(parameters('storageAccountName'), '/default/', parameters('containerNames')[copyIndex()])]",
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2018-03-01-preview",
"dependsOn": [
"[parameters('storageAccountName')]"
],
"copy": {
"name": "containercopy",
"count": "[length(parameters('containerNames'))]"
}
}
],
"outputs": {
"storageAccountName": {
"type": "string",
"value": "[parameters('storageAccountName')]"
},
"storageAccountKey": {
"type": "string",
"value": "[listKeys(parameters('storageAccountName'), '2018-02-01').keys[0].value]"
},
"storageContainerNames": {
"type": "array",
"value": "[parameters('containerNames')]"
}
}
}
Input can be e.g.
-storageAccountName 'stor1' -containerNames [ 'con1', 'con2' ] -location 'westeurope'
In an next step I create Stored Access Policies for the containers deployed.
Problem:
The first time I do that everything works fine. But if I execute the pipeline a second time the Stored Access Policies gets deleted by the deployment of the template. The storage account itself with its containers and blobs are not deleted (as it should be). This is unfortunate because I want to keep the Stored Access Policy with its starttime and expirytime as deployed the first time, furthermore I expect that the SAS also become invalid (not tested so far).
Questions:
Why is this happening?
How can I avoid this problem respectively keep the Stored Access Policies?
Thanks
After doing some investigation this seems to be by design. When deploying ARM templates for storage accounts the PUT operation is used, i.e. elements that are not specified within the template are removed. As it is not possible to specify Shared Access Policies for containers within an ARM template for Storage Accounts existing ones get deleted when the template is redeployed...

Kubernetes - Job scheduling API

I am trying to schedule Jobs in Kubernetes.
https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
The job can be created using the below command.
$ kubectl create -f ./cronjob.yaml
cronjob "hello" created
Is there any REST API using which the Job can be created from a Java client?
Thanks
The respective REST endpoint is described in the official API reference. You will find the CronJob resource in the batch/v1beta1 API group. To create a new CronJob resource, you'll need a POST call to the /apis/batch/v1beta1/namespaces/{namespace}/cronjobs URL.
A respective HTTP request might look something like this:
POST /apis/batch/v1beta1/namespaces/default/cronjobs HTTP/1.1
Content-Type: application/json
Content-Length: ...
Authorization: ...
[other headers]
{
"metadata": {
"name": "some-cron"
},
"spec": {
...
}
}
There are also older versions of the same resource, for example in the batch/v2alpha1 API group. As a rule of thumb, I'd recommend using the newest API version available to you. Especially, do not rely on alpha APIs in production; they tend to deprecate pretty quickly between releases.
To create a batch/v1beta1 CronJob using the Java client, have a look at the createNamespacedCronJob method of the io.kubernetes.client.openapi.apis.BatchV1beta1Api class.
HTTP Request
POST /apis/batch/v1beta1/namespaces/{namespace}/cronjobs
You can take a look here for API overview: cronjob-v1beta1-batch
Add CronJob object in request Body.
{
"apiVersion": "batch/v1beta1",
"kind": "CronJob",
"metadata": {
"name": "hello"
},
"spec": {
"schedule": "*/1 * * * *",
"jobTemplate": {
}
}
}
Check here its spec: writing-a-cron-job-spec
Part of swagger.json
"post": {
"description": "create a CronJob",
"consumes": [
"*/*"
],
"produces": [
"application/json",
"application/yaml",
"application/vnd.kubernetes.protobuf"
],
"schemes": [
"https"
],
"tags": [
"batch_v1beta1"
],
"operationId": "createBatchV1beta1NamespacedCronJob",
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/io.k8s.api.batch.v1beta1.CronJob"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/io.k8s.api.batch.v1beta1.CronJob"
}
},
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/io.k8s.api.batch.v1beta1.CronJob"
}
},
"202": {
"description": "Accepted",
"schema": {
"$ref": "#/definitions/io.k8s.api.batch.v1beta1.CronJob"
}
},
"401": {
"description": "Unauthorized"
}
},
"x-kubernetes-action": "post",
"x-kubernetes-group-version-kind": {
"group": "batch",
"kind": "CronJob",
"version": "v1beta1"
}
}
See full swagger.json