The following DSC statements duplicate existing Windows Firewall Rules instead of just updating the same rules which already exist. I would prefer it update instead of duplicate. Thanks
xFirewall EnableV4PingIn{
Name = 'File and Printer Sharing (Echo Request - ICMPv4-In)'
Group= 'File and Printer Sharing'
Protocol = 'ICMPv4'
Ensure='Present'
Enabled='True'
Direction='Inbound'
PsDscRunAsCredential = $DomainAdminCredential
}
xFirewall EnableV4PingOut{
Name = 'File and Printer Sharing (Echo Request - ICMPv4-Out)'
Group= 'File and Printer Sharing'
Protocol = 'ICMPv4'
Ensure='Present'
Enabled='True'
Direction='Outbound'
PsDscRunAsCredential = $DomainAdminCredential
}
xFirewall EnableV6PingIn{
Name = 'File and Printer Sharing (Echo Request - ICMPv6-In)'
Group= 'File and Printer Sharing'
Protocol = 'ICMPv6'
Ensure='Present'
Enabled='True'
Direction='Inbound'
PsDscRunAsCredential = $DomainAdminCredential
}
xFirewall EnableV6PingOut{
Name = 'File and Printer Sharing (Echo Request - ICMPv6-Out)'
Group= 'File and Printer Sharing'
Protocol = 'ICMPv6'
Ensure='Present'
Enabled='True'
Direction='Outbound'
PsDscRunAsCredential = $DomainAdminCredential
}
I figured it out :)
It turns out that the "Name" in xFirewall does not map to the "Name" shown in the GUI for the Windows Firewall.
You can run the following command to see the available rules (and their real "names"):
Get-NetFirewallRule |ft
So, your above can be simplified to the following (for v4):
xFirewall EnableV4PingIn
{
Name = "FPS-ICMP4-ERQ-In"
Enabled = "True"
}
xFirewall EnableV4PingOut
{
Name = "FPS-ICMP4-ERQ-Out"
Enabled = "True"
}
Related
Just inquiring if anyone's aware of any permission limitations with the PagerDuty terraform API? With a base role of Observer in PagerDuty, it appears as though certain objects (which my user created) can be deleted via the GUI, but not via the terraform API even though I’m using the same user account. A PagerDuty Extension is an example of an object where I’m hitting this issue.
The same test case works as expected if I try it with a user with a base role of Manager though. Here’s a quick terraform file I threw together to verify this test case:
resource "pagerduty_schedule" "schedule" {
name = "terraform-test-schedule"
time_zone = "America/Denver"
teams = ["PRDBAEK"]
layer {
name = "weekly"
start = "2020-02-05T09:00:00-06:00"
rotation_virtual_start = "2020-02-05T09:00:00-06:00"
rotation_turn_length_seconds = 604800
users = ["PN94M6Q"]
}
}
resource "pagerduty_escalation_policy" "escalation_policy" {
name = "terraform-test-ep"
description = "terraform-test-ep"
num_loops = 0
teams = ["PRDBAEK"]
rule {
escalation_delay_in_minutes = 10
target {
type = "schedule_reference"
id = pagerduty_schedule.schedule.id
}
}
}
resource "pagerduty_service" "event" {
name = "terraform-test-service"
description = "terraform-test-service"
alert_creation = "create_alerts_and_incidents"
escalation_policy = pagerduty_escalation_policy.escalation_policy.id
incident_urgency_rule {
type = "constant"
urgency = "severity_based"
}
alert_grouping_parameters {
type = "intelligent"
config {
fields = []
timeout =0
}
}
auto_resolve_timeout = "null"
acknowledgement_timeout = "null"
}
resource "pagerduty_extension" "test_extension" {
name = "terraform-test-extension"
extension_schema = data.pagerduty_extension_schema.generic_v2_webhook.id
endpoint_url = https://fakeurl.com
extension_objects = [
pagerduty_service.event.id
]
config = jsonencode({})
}
All objects can be created successfully. I get the following error when testing a terraform destroy with an account with base role Observer though. It can't delete the Extension.
Error: DELETE API call to https://api.pagerduty.com/extensions/P53423F failed 403 Forbidden. Code: 2010, Errors: <nil>, Message: Access Denied
But using that same account, I can delete that extension in the GUI with no issues.
I have a Terraform configuration (v0.14, AWS provider 3.32.0) in which I have defined the parameters for certain resource types as objects (input variables). Here is an (simplified) example:
variable "docker_config" {
type = object({
internal = number
external = number
protocol = string
})
default =
{
internal = 8300
external = 8300
protocol = "tcp"
}
}
However, I would like to be able to override individual values via command line or environment variable.
Can I overwrite individual values of the object without having to pass the whole object? So, use default values and override them as needed:
e. g.
TF_VAR_docker_config.internal = 1234
or
TF_VAR_docker_config = "{internal = 1234}"
And this would result in:
{
internal = 1234
external = 8300
protocol = "tcp"
}
My tests did not work. Is it possible? If yes, how?
Sadly, you can't do this directly. In near future optional should be added to object which will simplify this.
For now, a non-perfect workaround could be to use merge with regular map:
variable "docker_config_default" {
type = object({
internal = number
external = number
protocol = string
})
default = {
internal = 8300
external = 8300
protocol = "tcp"
}
}
variable "docker_config" {
type = map
validation {
# condition is not perfect and suited only for one
# attribute overwrite
condition = (can(var.docker_config["internal"])
|| can(var.docker_config["external"])
|| can(var.docker_config["protocol"]))
error_message = "Must have internal, external or protocol."
}
}
locals {
docker_config = merge(var.docker_config_default, var.docker_config)
}
output "test" {
value = local.docker_config
}
And you just use local.docker_config in your code.
Reading through the docs here:
https://www.terraform.io/docs/providers/google/r/compute_backend_service.html
We can define backend service:
resource "google_compute_backend_service" "kubernetes-nginx-prod" {
name = "kubernetes-nginx-prod"
health_checks = [google_compute_health_check.kubernetes-nginx-prod-healthcheck.self_link]
backend {
group = replace(google_container_node_pool.pool-1.instance_group_urls[0], "instanceGroupManagers", "instanceGroups")
# TODO missing port 31443
}
}
It seems we are unable to set backend service port via the Terraform settings:
Recreating the backend service without this settings actually leads to downtime for us and the port must be written manually.
We need to reference the port name that we gave in the instance group for e.g.
resource "google_compute_backend_service" "test" {
name = "test-service"
port_name = "test-port"
protocol = "HTTP"
timeout_sec = 5
health_checks = []
backend {
group = "${google_compute_instance_group.test-ig.self_link}"
}
}
resource "google_compute_instance_group" "test-ig" {
name = "test-ig"
instances = []
named_port {
name = "test-port"
port = "${var.app_port}"
}
zone = "${var.zone}"
}
I resolved this by using a terraform data source to extract the instance group data from my google_container_node_pool, and then appending a google_compute_instance_group_named_port resource to it.
NOTE my google_container_node_pool spans 3 zones (a,b,c) and the below code highlights the solution for only zone c
# extract google_compute_instance_group from google_container_node_pool
data "google_compute_instance_group" "instance_group_zone_c" {
# .2 refers to the last of the 3 instance groups in my node pool (zone c)
name = regex("([^/]+)/?$", "${google_container_node_pool.k8s_node_pool.instance_group_urls.2}").0
zone = regex("${var.region}-?[abc]", "${google_container_node_pool.k8s_node_pool.instance_group_urls.2}")
project = var.project_id
}
# define a named port to attach to the google_compute_instance group in my node pool
resource "google_compute_instance_group_named_port" "named_port_zone_c" {
group = data.google_compute_instance_group.instance_group_zone_c.id
zone = data.google_compute_instance_group.instance_group_zone_c.zone
name = "port31090"
port = 31090
}
I have a Containerized Network Function (CNF) that connects to three Docker Networks:
...
ip_address = "172.17.0.3"
ip_prefix_length = 16
ipc_mode = "private"
log_driver = "json-file"
log_opts = {}
logs = false
max_retry_count = 0
memory = 4096
memory_swap = -1
must_run = true
name = "c-router-52"
network_data = [
{
gateway = "172.17.0.1"
ip_address = "172.17.0.3"
ip_prefix_length = 16
network_name = "bridge"
},
{
gateway = "172.31.0.1"
ip_address = "172.31.0.4"
ip_prefix_length = 16
network_name = "inside-net"
},
{
gateway = "172.30.0.1"
ip_address = "172.30.0.3"
ip_prefix_length = 16
network_name = "outside-net"
},
]
network_mode = "default"
...
And I am trying to grab the 'outside-net' IP address for use as an input for another container. I am specifying like so:
${docker_container.c-router-52.network_data[2].ip_address}
When its the third element, it works fine.... But the problem is that Terraform (or Docker, one of the two) doesn't always put the 'outside-net' as the third network :(
Is there a way to specify the [network_name="outside-net"] rather than an index number?
Since your code example isn't complete I'm having to guess a little here, but it seems like what you want is a mapping from network name to IP address. You can derive such a data structure from your resource configuration using a for expression, which you can assign to a local value for use elsewhere in the configuration:
locals {
container_ip_addresses = {
for net in docker_container.c-router-52.network_data :
net.network_name => net.ip_address
}
}
With the above definition in your module, you can refer to local.container_ip_addresses elsewhere in your module to refer to this mapping, such as local.container_ip_addresses["outside-net"] to access the outside-net address in particular.
With the network_data structure you showed in your configuration, local.container_ip_addresses would have the following value:
{
bridge = "172.17.0.3"
inside-net = "172.31.0.4"
outside-net = "172.30.0.3"
}
If you need to access the other attributes of those network_data objects, rather than just the ip_address, you can generalize this by making the values of the mapping be the full network objects:
locals {
container_networks = {
for net in docker_container.c-router-52.network_data :
net.network_name => net
}
}
...which would then allow you to access all of the attributes via the network name keys:
local.container_networks["outside-net"].ip_address
local.container_networks["outside-net"].gateway
local.container_networks["outside-net"].ip_prefix_length
I am writing a Terraform script to spin up resources in Google Cloud Platform.
Some resources require one argument only if the other one set, how to populate one argument only if the other one is populated (or any other similar condition)?
For example:
resource "google_compute_router" "compute_router" {
name = "my-router"
network = "${google_compute_network.foobar.name}"
bgp {
asn = 64514
advertise_mode = "CUSTOM"
advertised_groups = ["ALL_SUBNETS"]
advertised_ip_ranges {
range = "1.2.3.4"
}
advertised_ip_ranges {
range = "6.7.0.0/16"
}
}
}
In the above resource (google_compute_router) the description for both advertised_groups and advertised_ip_ranges says This field can only be populated if advertise_mode is CUSTOM and is advertised to all peers of the router.
Now if I keep the value of advertise_mode as DEFAULT, my code looks something like below:
resource "google_compute_router" "compute_router" {
name = "my-router"
network = "${google_compute_network.foobar.name}"
bgp {
asn = 64514
#Changin only the value below
advertise_mode = "DEFAULT"
advertised_groups = ["ALL_SUBNETS"]
advertised_ip_ranges {
range = "1.2.3.4"
}
advertised_ip_ranges {
range = "6.7.0.0/16"
}
}
}
The above script however on running gives the following error:
* google_compute_router.compute_router_default: Error creating Router: googleapi: Error 400: Invalid value for field 'resource.bgp.advertiseMode': 'DEFAULT'. Router cannot have a custom advertisement configurati
on in default mode., invalid
As a workaround to the above, I have created two resources with different names doing almost the same thing. The script looks something like below:
resource "google_compute_router" "compute_router_default" {
count = "${var.advertise_mode == "DEFAULT" ? 1 : 0}"
name = "${var.router_name}"
region = "${var.region}"
network = "${var.network_name}"
bgp {
asn = "${var.asn}"
advertise_mode = "${var.advertise_mode}"
#Removed some codes from here
}
}
resource "google_compute_router" "compute_router_custom" {
count = "${var.advertise_mode == "CUSTOM" ? 1 : 0}"
name = "${var.router_name}"
region = "${var.region}"
network = "${var.network_name}"
bgp {
asn = "${var.asn}"
advertise_mode = "${var.advertise_mode}"
advertised_groups = ["${var.advertised_groups}"]
advertised_ip_ranges {
range = "${var.advertised_ip_range}"
description = "${var.advertised_ip_description}"
}
}
}
The above script works fine, however it seems like a lot of code repetition to me and a hack. Also, for two options (of dependent attributes) is fine, however, if there are more options say 5, the code repetition for such a small thing would be too much.
Is there a better way to do what I am trying to achieve?
This is pretty much what you are restricted to in Terraform < 0.12. Some resources allow you to use an empty string to omit basic values and the provider will interpret this as a null value, not passing it to the API endpoint so it won't complain about it not being set properly. But from my brief experience with the GCP provider this is not the case for most things there.
Terraform 0.12 introduces nullable arguments which would allow you to set these conditionally with something like the following:
variable "advertise_mode" {}
resource "google_compute_router" "compute_router" {
name = "my-router"
network = "${google_compute_network.foobar.name}"
bgp {
asn = 64514
advertise_mode = "${var.advertise_mode}"
advertised_groups = ["${var.advertise_mode == "DYNAMIC" ? ALL_SUBNETS : null}"]
advertised_ip_ranges {
range = "${var.advertise_mode == "DYNAMIC" ? 1.2.3.4 : null}"
}
advertised_ip_ranges {
range = "${var.advertise_mode == "DYNAMIC" ? 6.7.0.0/16 : null}"
}
}
}
It will also introduce dynamic blocks that you are able to loop over so you can also have a dynamic number of advertised_ip_ranges blocks.
The above answer is incorrect as 'advertised_ip_ranges' wont accept a null value; the solution to this is to leverage a dynamic block which can handle a null value for this resource and further enables the resource to accept a variable number of ip ranges.
variable custom_ranges {
default = ["172.16.31.0/24","172.16.32.0/24"]
}
resource "google_compute_router" "router_01" {
name = "cr-bgp-${var.gcp_bgp_asn}"
region = var.gcp_region
project = var.gcp_project
network = var.gcp_network
bgp {
asn = var.gcp_bgp_asn
advertise_mode = var.advertise_mode
advertised_groups = var.advertise_mode == "CUSTOM" ? ["ALL_SUBNETS"] : null
dynamic "advertised_ip_ranges" {
for_each = var.advertise_mode == "CUSTOM" ? var.custom_ranges : []
content {
range = advertised_ip_ranges.value
}
}
}
}
additional search keys: google_compute_router "bgp.0.advertised_ip_ranges.0.range" wont accept a null value.