Azure Apim. Create operation in schema from openapi definition - azure

I have to create a schema so then I can create operation in Azure APIM. the code that I know is need to be used is:
resource "azurerm_api_management_api_schema" "example" {
api_name = azurerm_api_management_api.sample-api.name
api_management_name = azurerm_api_management_api.sample-api.api_management_name
resource_group_name = azurerm_api_management_api.sample-api.resource_group_name
schema_id = "example-schema"
content_type = "application/vnd.oai.openapi.components+json"
value = <<JSON
{
"properties": {
"contentType": "application/vnd.oai.openapi.components+json",
"document": {
"components": {
"schemas": {
operation Get 1
operation Get 2
operation post 1.....
but how Im supposed to extract Get and POST operations from this openapi definition and include them in that Schema?
https://github.com/RaphaelYoshiga/TerraformBasics/blob/master/conference-api.json
I havenĀ“t find a clear example so far .

Below is the example of Azure apim operation with apim service
data "azurerm_api_management_api" "example" {
name = "search-api"
api_management_name = "search-api-management"
resource_group_name = "search-service"
revision = "2"
}
resource "azurerm_api_management_api_operation" "example" {
operation_id = "user-delete"
api_name = data.azurerm_api_management_api.example.name
api_management_name = data.azurerm_api_management_api.example.api_management_name
resource_group_name = data.azurerm_api_management_api.example.resource_group_name
display_name = "Delete User Operation"
method = "DELETE"
url_template = "/users/{id}/delete"
description = "This can only be done by the logged in user."
response {
status_code = 200
}
}
For further information check this.

Related

Azure Activity Log Alerts are not working

I have created an Activity Log Alert in Azure using the following Terraform Code
// We need to define the action group for Security Alerts
resource "azurerm_monitor_action_group" "monitor_action_group_soc" {
name = "sec-alert"
resource_group_name = data.azurerm_resource_group.tenant-global.name
short_name = "sec-alert"
email_receiver {
name = "sendtoAdmin"
email_address = var.email_address
use_common_alert_schema = true
}
}
data "azurerm_monitor_action_group" "monitor_action_group_soc" {
name = "sec-alert"
resource_group_name = var.tenant-global-rg
depends_on = [
azurerm_monitor_action_group.monitor_action_group_soc
]
}
// Monitor Activity Log and Alert
resource "azurerm_monitor_activity_log_alert" "activity_log_alert_cu_security_group" {
name = "Activity Log Alert for Create or Update Security Group"
resource_group_name = data.azurerm_resource_group.ipz12-dat-np-mgmt-rg.name
scopes = [data.azurerm_subscription.current.id]
description = "Monitoring for Create or Update Network Security Group events gives insight into network access changes and may reduce the time it takes to detect suspicious activity"
criteria {
category = "Security"
operation_name = "Microsoft.Network/networkSecurityGroups/write"
}
action {
action_group_id = data.azurerm_monitor_action_group.monitor_action_group_soc.id
}
}
I have created the Network Security Group, added a Rule, deleted the Rule and finally deleted the Network Security Group but I didn't receive any Alerts.
Azure Activity Log Alerts are not working:
These are the modifications I made to your code to achieve the expected result.
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "<resourcegroup>"{
name = "<resourcegroup>"
location = "Central US"
}
resource "azurerm_monitor_action_group" "<actiongroup>" {
name = "sec-alert"
resource_group_name = "<resourcegroup>"
short_name = "sec-alert"
email_receiver {
name = "xxxxx"
email_address = "xxxxxxx#gmail.com"
use_common_alert_schema = true
}
}
data "azurerm_monitor_action_group" "<actiongroup>" {
name = "sec-alert"
resource_group_name = "<resourcegroup>"
depends_on = [
azurerm_monitor_action_group.<actiongroup>
]
}
resource "azurerm_monitor_activity_log_alert" "azurerm_monitor_activity_log_alert_securitygroup" {
name = "Activity Log Alert for Create or Update Security Group"
resource_group_name = "<resourcegroup>"
scopes = [data.azurerm_subscription.current.id] #My scope is /subscriptions/<subscriptionID>/resourceGroups/<resourcegroup>/providers/Microsoft.Network/networkSecurityGroups/<NetworkSecurityGroup>
description = "Monitoring for Create or Update Network Security Group events gives insight into network access changes and may reduce the time it takes to detect suspicious activity"
criteria {
category = "Security"
operation_name = "Microsoft.Network/networkSecurityGroups/write"
}
action {
action_group_id = data.azurerm_monitor_action_group.<actiongroup>.id
}
}
Created Security alert by running "terraform apply" in AzCLI :
Received a mail once it is added to the Network Security Group:

Unable to pass variable from .tf file to .json policy template

I'm a newbe to terraform world and experiencing some tough time around passing variables from .tf file to .json
My sample tf lambda function is as follows
data "template_file" "task" {
template = file("./iam/grange_rest_dynlambda_policy.json")
vars = {
resource="${var.stage}_grange_dynamodb"
}
}
resource "aws_lambda_function" "grange_rest_dynlambda" {
function_name = "${var.stage}_grange_rest_dynlambda"
handler = "lambda/src/index.handler"
memory_size = "256"
timeout = 10
reserved_concurrent_executions = "-1"
filename = "${path.module}/../dist/lambda.zip"
role = aws_iam_role.grange_rest_dynlambda_iam_role.arn
runtime = "nodejs14.x"
publish = true
}
resource "aws_lambda_alias" "grange_rest_dynlambda_alias" {
depends_on = ["aws_lambda_function.grange_rest_dynlambda"]
name = var.stage
description = var.stage
function_name = aws_lambda_function.grange_rest_dynlambda.arn
function_version = aws_lambda_function.grange_rest_dynlambda.version
}
// Enable cloudwatch for lambda
resource "aws_cloudwatch_log_group" "example" {
name = "/aws/lambda/${var.stage}_grange_rest_dynlambda"
retention_in_days = 14
}
# See also the following AWS managed policy: AWSLambdaBasicExecutionRole
resource "aws_iam_policy" "lambda_logging" {
name = "lambda_logging"
path = "/"
description = "IAM policy for logging from a lambda"
policy = file("./iam/grange_rest_dynlambda_logging_policy.json")
}
// Lambda + DynamoDB
resource "aws_iam_role" "grange_rest_dynlambda_iam_role" {
name = "grange_rest_dynlambda_iam_role"
assume_role_policy = file("./iam/grange_rest_dynlambda_assume_policy.json")
}
resource "aws_iam_role_policy" "grange_rest_dynlambda_iam_policy" {
policy = file("./iam/grange_rest_dynlambda_policy.json")
role = aws_iam_role.grange_rest_dynlambda_iam_role.id
}
resource "aws_iam_role_policy_attachment" "lambda_logs" {
role = aws_iam_role.grange_rest_dynlambda_iam_role.name
policy_arn = aws_iam_policy.lambda_logging.arn
}
// API Gateway + Lambda
resource "aws_api_gateway_resource" "grange_rest_dynlambda_api" {
parent_id = aws_api_gateway_rest_api.grange_rest_api_gateway.root_resource_id
path_part = "grange_rest_dynlambda_api"
rest_api_id = aws_api_gateway_rest_api.grange_rest_api_gateway.id
}
resource "aws_api_gateway_method" "grange_rest_dynlambda_api_get" {
authorization = "NONE"
http_method = "GET"
resource_id = aws_api_gateway_resource.grange_rest_dynlambda_api.id
rest_api_id = aws_api_gateway_rest_api.grange_rest_api_gateway.id
}
resource "aws_api_gateway_method" "grange_rest_dynlambda_api_post" {
authorization = "NONE"
http_method = "POST"
resource_id = aws_api_gateway_resource.grange_rest_dynlambda_api.id
rest_api_id = aws_api_gateway_rest_api.grange_rest_api_gateway.id
}
resource "aws_lambda_permission" "apigw" {
action = "lambda:InvokeFunction"
statement_id = "AllowExecutionFromAPIGateway"
function_name = aws_lambda_function.grange_rest_dynlambda.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_api_gateway_rest_api.grange_rest_api_gateway.execution_arn}/*/*"
}
output "base_url" {
value = aws_api_gateway_deployment.apigwdeployment.invoke_url
}
I inject policy from a JSON file and expect "resource" variable to be passed into JSON. But, that's not how it works
{
"Version": "2012-10-17",
"Statement":[{
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:GetItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:us-east-2:741573820784:table/${resource}"
}
]
}
What am I missing?
The template_file data source does not replace the variables in the actual file. It just reads the file and provides the "rendered" output directly to your Terraform.
Therefore, you need to change your Terraform where you want to consume the "rendered" output:
Before:
resource "aws_iam_role_policy" "grange_rest_dynlambda_iam_policy" {
policy = file("./iam/grange_rest_dynlambda_policy.json")
role = aws_iam_role.grange_rest_dynlambda_iam_role.id
}
After:
resource "aws_iam_role_policy" "grange_rest_dynlambda_iam_policy" {
policy = data.template_file.task.rendered
role = aws_iam_role.grange_rest_dynlambda_iam_role.id
}
You need to access the rendered property of the template_file data source:
data.template_file.task.rendered
This will replace ${resource} with the value of "${var.stage}_grange_dynamodb".
Please note, that the documentation recommends to use the templatefile function instead of this data source.

Terraform azurerm_api_management_api bumping revision does not apply all required changes

We are managing our API Management platform in Azure with terraform. Sometimes we need to bump the revision, and when we do that there are several issues:
The API that gets bumped is recreated (expected)
The recreated API is lost from all products it belonged to
The recreated API does not get any policies applied
So when the revision is bumped, the pipeline has to be run twice:
The API is recreated
The API is added to the product again and gets its policy applied
This is how the template looks like:
# Fetch existing API management instance
data "azurerm_api_management" "storemanager_api_management" {
name = local.api_management_name
resource_group_name = local.api_management_resource_group_name
}
# Create the API
resource "azurerm_api_management_api" "api" {
api_management_name = data.azurerm_api_management.storemanager_api_management.name
resource_group_name = local.api_management_resource_group_name
name = "api"
path = "api"
display_name = "api 1"
protocols = ["https"]
revision = var.api_revision
subscription_required = true
subscription_key_parameter_names {
header = local.api_subscription_key_name
query = local.api_subscription_key_name
}
import {
content_format = "swagger-link-json"
content_value = format("https://%s.blob.core.windows.net/%s/%s/%s",
data.azurerm_storage_account.storage_account.name,
data.azurerm_storage_container.open_api_definition_storage_container.name,
var.api_api_version,
local.api_api_definition_name
)
}
}
# Create the product
resource "azurerm_api_management_product" "product" {
api_management_name = data.azurerm_api_management.storemanager_api_management.name
resource_group_name = local.api_management_resource_group_name
product_id = "product"
display_name = "Product"
description = "Collection of APIs"
subscription_required = true
subscriptions_limit = 1
approval_required = true
published = true
}
# Associate the API with the product
resource "azurerm_api_management_product_api" "product_api" {
api_management_name = data.azurerm_api_management.storemanager_api_management.name
resource_group_name = local.api_management_resource_group_name
product_id = azurerm_api_management_product.product.product_id
api_name = azurerm_api_management_api.api.name
}
# Apply policy to the API
resource "azurerm_api_management_api_policy" "policy" {
api_name = azurerm_api_management_api.api.name
api_management_name = data.azurerm_api_management.storemanager_api_management.name
resource_group_name = local.api_management_resource_group_name
xml_content = templatefile("./policy.tmpl", { x_functions_key_value = var.function_key, backend_name = azurerm_api_management_backend.generic_function_app_backend.name })
}
Is this a bug, or am I not using terraform correctly? How do I re-add the recreated API to the product and get its policy applied in one run of the pipeline?

AWS API Gateway Appending Query String Twice

I am trying to setup a simple demo endpoint via AWS API Gateway. Bellow is Terraform manifest which describes it.
It is essentially a GET /demo/hello/world endpoint which accepts a query string parameter return_to.
The terraform correctly creates all resources in AWS.
However, when I then make a request to gateway at /demo/hello/world?return_to=bbb, the backend service receives this request:
/demo/hello/world%3Freturn_to=bbb?return_to=bbb
As you can see the ?return_to=bbb from API Gateway is being URL encoded as if it were part of the path and then another query string is appended at the end.
Anybody could help me out how to fix this? I have been going through all the settings for few hours and can't figure out what is the issue and how to fix it.
resource "aws_api_gateway_rest_api" "api" {
name = "origin-${var.name}.${data.terraform_remote_state.setup.outputs.domain-name}"
description = "Proxy to handle requests to our API test"
}
resource "aws_api_gateway_resource" "demo" {
depends_on = ["aws_api_gateway_rest_api.api"]
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
parent_id = "${aws_api_gateway_rest_api.api.root_resource_id}"
path_part = "demo"
}
resource "aws_api_gateway_resource" "hello" {
depends_on = ["aws_api_gateway_rest_api.api", "aws_api_gateway_resource.demo"]
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
parent_id = "${aws_api_gateway_resource.demo.id}"
path_part = "hello"
}
resource "aws_api_gateway_resource" "world" {
depends_on = ["aws_api_gateway_rest_api.api", "aws_api_gateway_resource.hello"]
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
parent_id = "${aws_api_gateway_resource.hello.id}"
path_part = "world"
}
resource "aws_api_gateway_method" "hello-world" {
depends_on = ["aws_api_gateway_resource.world"]
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
resource_id = "${aws_api_gateway_resource.world.id}"
http_method = "GET"
authorization = "NONE"
request_parameters = {
"method.request.querystring.return_to" = true
}
}
resource "aws_api_gateway_integration" "hello-world" {
depends_on = ["aws_api_gateway_method.hello-world"]
rest_api_id = "${aws_api_gateway_rest_api.api.id}"
resource_id = "${aws_api_gateway_resource.world.id}"
http_method = "${aws_api_gateway_method.hello-world.http_method}"
integration_http_method = "GET"
type = "HTTP"
uri = "http://${lookup(var.demo-map, var.environment)}/demo/hello/world"
connection_type = "VPC_LINK"
connection_id = "${data.aws_api_gateway_vpc_link.vpclink.id}"
request_parameters = {
"integration.request.querystring.return_to" = "method.request.querystring.return_to"
}
}
I had the same error. Having the query parameters in the aws_api_gateway_method and removing from aws_api_gateway_integration solved my problem

Azure Alert Creation Via terraform fails with error code 400

While creating metric alert on storage account via terraform I am getting Error 400
I've gone through the documentation and corss-verified that the name I am using for alert creation is correct
resource "azurerm_metric_alertrule" "test" {
name = "alerttestacc"
resource_group_name = "${azurerm_resource_group.main.name}"
location = "${azurerm_resource_group.main.location}"
description = "An alert rule to watch the metric Used capacity"
enabled = true
resource_id = "${azurerm_storage_account.to_monitor.id}"
metric_name = "UsedCapacity"
operator = "GreaterThan"
threshold = 20
aggregation = "Total"
period = "PT5M"
email_action {
send_to_service_owners = false
custom_emails = [
"xyz#gmail.com",
]
}
webhook_action {
service_uri = "https://example.com/some-url"
properties = {
severity = "incredible"
acceptance_test = "true"
}
}
Expected: Alert should be created
Actual:
azurerm_metric_alertrule.test:
insights.AlertRulesClient#CreateOrUpdate: Failure responding to
request: StatusCode=400 -- Original Error: autorest/azure: Service
returned an error. Status=400 Code="UnsupportedMetric" Message="The
metric with namespace '' and name 'UsedCapacity' is not supported for
this resource id
You could use azurerm_monitor_metric_alert instead of azurerm_metric_alertrule to create a UsedCapacity metric alert for the storage account. It is possible due to the different experiences between classic alerts and new alerts in Azure monitoring. Read alerts overview.
This example works on my side.
resource "azurerm_resource_group" "main" {
name = "example-resources"
location = "West US"
}
resource "azurerm_storage_account" "to_monitor" {
name = "examplestorageaccount123"
resource_group_name = "${azurerm_resource_group.main.name}"
location = "${azurerm_resource_group.main.location}"
account_tier = "Standard"
account_replication_type = "LRS"
}
resource "azurerm_monitor_action_group" "main" {
name = "example-actiongroup"
resource_group_name = "${azurerm_resource_group.main.name}"
short_name = "exampleact"
webhook_receiver {
name = "callmyapi"
service_uri = "http://example.com/alert"
}
}
resource "azurerm_monitor_metric_alert" "test" {
name = "example-metricalert"
resource_group_name = "${azurerm_resource_group.main.name}"
scopes = ["${azurerm_storage_account.to_monitor.id}"]
description = "Action will be triggered when the Used capacity is Greater than 777 bytes."
criteria {
metric_namespace = "Microsoft.Storage/storageAccounts"
metric_name = "UsedCapacity"
aggregation = "Total"
operator = "GreaterThan"
threshold = 777
}
action {
action_group_id = "${azurerm_monitor_action_group.main.id}"
}
}

Resources