英文:
terraform dynamic block based on variable
问题
以下是代码部分的翻译:
我目前有一个构建存储帐户的模块
```hcl
resource "azurerm_storage_account" "data_lake_storage" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
account_tier = var.sku
account_replication_type = var.redundancy
is_hns_enabled = true
tags = var.tags
}
我们的开发人员会在他们的本地机器上运行terraform apply,以构建一个用于开发的环境。完成后,他们将检入他们的代码,然后我们的代理机器将运行terraform来构建我们的开发、QA和生产环境。
我的问题现在是,我需要锁定我们的存储帐户并拒绝公共访问。所以我需要修改存储帐户如下:
resource "azurerm_storage_account" "data_lake_storage" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
account_tier = var.sku
account_replication_type = var.redundancy
is_hns_enabled = true
tags = var.tags
network_rules {
default_action = "Deny"
virtual_network_subnet_ids = [
var.agent_vnet_id,
var.dbr_private_subnet_id,
var.dbr_public_subnet_id
]
bypass = ["None"]
}
}
当代理运行terraform时,这将起作用,但当开发人员在本地运行terraform时,将不起作用,因为他们的IP地址不在列表中。为了让它对他们起作用,我需要:
network_rules {
default_action = "Deny"
ip_rules = [var.client_ip_address]
virtual_network_subnet_ids = [azurerm_subnet.dbr-public.id, azurerm_subnet.dbr-private.id]
bypass = ["None"]
}
我能想到的唯一解决方案是设置一个变量,指示是开发人员运行代码还是代理,并根据变量更改网络规则部分。但我不知道如何做到这一点。
除非我在方法上漏掉了一些明显的东西。
<details>
<summary>英文:</summary>
I currently have a module that builds a storage account
resource "azurerm_storage_account" "data_lake_storage" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
account_tier = var.sku
account_replication_type = var.redundancy
is_hns_enabled = true
tags = var.tags
}
Our developers will run terraform apply on their local machines to build themselves an environment to develop against. Once complete they will check in their code and our agent machines will run the terraform to build our dev, qa and live environments.
My problem now is that I need to lock down our storage account and deny public access. So I need to amend the storage account with the following
resource "azurerm_storage_account" "data_lake_storage" {
name = var.name
resource_group_name = var.resource_group_name
location = var.location
account_tier = var.sku
account_replication_type = var.redundancy
is_hns_enabled = true
tags = var.tags
network_rules {
default_action = "Deny"
virtual_network_subnet_ids = [
var.agent_vnet_id,
var.dbr_private_subnet_id,
var.dbr_public_subnet_id
]
bypass = ["None"]
}
}
This will work when the agents run the terraform but wont work when the developers run the terraform locally, as their IP address is not in the list. To allow it to work for them I would need:
network_rules {
default_action = "Deny"
ip_rules = [ var.client_ip_address ]
virtual_network_subnet_ids = [ azurerm_subnet.dbr-public.id, azurerm_subnet.dbr-private.id ]
bypass = [ "None" ]
}
The only solution I can think is to have a variable set to indicate whether it is a developer running the code or an agent and have the network rules section change depending on the variable. But I have no idea how to do that.
unless I am missing something obvious in my approach.
</details>
# 答案1
**得分**: 0
大多数Azure资源可以通过ARM通过互联网访问,但某些资源的子资源或配置属性需要访问资源本身,如存储帐户和密钥保管库。
当阻止互联网访问或限制对这些资源端点的网络访问时,Terraform运行的机器仍然需要访问这些资源端点。这意味着无论如何,Terraform运行的机器都需要网络连通性以访问这些资源端点。
许多团队希望开发人员在其本地开发机上运行Terraform CLI,以执行计划等操作,偶尔进行导入或其他状态管理操作,而应用操作则由流水线工具执行。
如果您的流水线工具运行其构建代理程序的服务器具有网络访问权限,但开发人员的工作站没有,您将遇到一个难题。如何让开发人员访问资源,同时保持私有网络关闭?
有几种解决方案。每种都有各自的权衡,有些比其他的更好。
首先,设计您的网络并设置点对站VPN以允许开发人员访问所需资源。这不是全盘承诺,如果有其他资源开发人员不需要访问,您可以设计网络和RBAC以将它们排除在外。
其次,这被称为网络限制三明治。其思路是:在运行Terraform之前,您可以打开网络以将单个机器的IP地址列入白名单,这可以是构建代理机器或开发工作站。这将允许他们运行Terraform。然后,在完成操作后,您可以删除此配置。因此,三明治的层次结构如下:网络配置更改,Terraform应用,网络配置更改。
在尝试了两者并亲身经历了第二个选项的痛苦后,我建议选择第一种选项。^_^
<details>
<summary>英文:</summary>
Most resources in Azure are accessible over the internet via ARM but some sub-resourxes or configuration attributes of a resource require access to the resource endpoint itself as those resources. Most notably are storage accounts and keyvaults.
When you block internet access or restrict network access to these resource endpoints whatever machine Terraform is running from still needs access to those resource endpoints. That means whatever machine Terraform is running on needs network line of sight to those resource endpoints.
Many teams expect developers to run Terraform CLI on their local development machine to do things like run plans and occasionally do imports or other state management operations while the apply is reserved for the pipeline tool.
If the server your pipeline tool runs it's build agent on has network access but your developers workstations do not you will run into a conundrum. How to grant developers access while keeping private network turned off?
There are a couple solutions to this. Each with their own trade offs. Some better than others.
First, design your network and setup Point-to-site VPN to allow developers access to the required resources. This is not an all or nothing deal if there are other resources your developers don't need access to you can design your network and RBAC in such a way to keep them out.
Second, it called a network restriction sandwich. The idea is this: before running Terraform you open up networking to whitelist a single machines IP address, this would be the build agent machine or the Dev workstations. This will allow them to run Terraform. Then after that is done you remove this configuration. So the layers of the sandwich are: network config change, Terraform apply, network config change.
Having tried both and dealt with the pain of the second option personally. I would recommend The first option. ^_^
</details>
# 答案2
**得分**: 0
好的,以下是翻译好的部分:
网络规则块如下所示:
```hcl
network_rules {
default_action = "Deny"
ip_rules = "${var.local_or_agent == "local" ? [var.client_ip_address] : null }"
virtual_network_subnet_ids = [
var.shared_vnet_id
]
bypass = ["None"]
}
接下来,我有两个变量声明,其默认值如下:
variable "client_ip_address" {
description = "客户端 IP 地址"
type = string
default = "1.1.1.1"
}
variable "local_or_agent" {
description = "客户端 IP 地址"
type = string
default = "agent"
}
然后,在开发人员运行的脚本中,我设置了这两个变量:
TF_VAR_client_ip_address=$(wget -q -O - ipinfo.io/ip)
export TF_VAR_client_ip_address
TF_VAR_local_or_agent="local"
export TF_VAR_local_or_agent
如果将这些变量从脚本中移除,它将仅创建带有 VNET 规则的存储账户。如果脚本中存在这些变量,它还会添加包含开发人员公共 IP 地址的 ip_rules。
英文:
OK so I got it working how I wanted to:
The network rules block looks like this
network_rules {
default_action = "Deny"
ip_rules = "${var.local_or_agent == "local" ? [var.client_ip_address] : null }"
virtual_network_subnet_ids = [
var.shared_vnet_id
]
bypass = ["None"]
}
I then have two variables declared with default values as follows
variable "client_ip_address" {
description = "client IP address"
type = string
default = "1.1.1.1"
}
variable "local_or_agent" {
description = "client IP address"
type = string
default = "agent"
}
Then in the script the developers run to create their environments I set those two variables
TF_VAR_client_ip_address=$(wget -q -O - ipinfo.io/ip)
export TF_VAR_client_ip_address
TF_VAR_local_or_agent="local"
export TF_VAR_local_or_agent
If those variables are removed from the script it creates the storage account with only the vnet rule. If those variables in the scrip are present it also adds the ip_rules with the developers public ip address.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论