How to programmatically use your public Internet IP address in Terraform?
Programmatically use your public IP in Terraform as source IP for AWS Security Rules #
While testing Terraform plans, sometimes there is a need to create firewall rules that use your current public Internet IP address, for example for SSH access to the created instances.
Updates:
- 2020 Jun 29: Upgraded to Terraform 0.12
- 2020 Oct 19: Set IPV4 switch -4 in dig command as suggested by Reque.
There is an easy way to programmatically obtain the IP address using a Terraform External Data Source.
Create a shell script that obtains the IP address and returns the value in a JSON object.
whatismyip.sh
#!/bin/bash
...
set -e
INTERNETIP="$(dig +short myip.opendns.com @resolver1.opendns.com -4)"
echo $(jq -n --arg internetip "$INTERNETIP" '{"internet_ip":$internetip}')
Call the external data source and use the output in a firewall rule. The example in aws_security_group_rules.tf shows how to use the public IP address in an AWS security rule created by Terraform to allow SSH access.
aws_security_group_rules.tf
data "external" "whatismyip" {
program = ["/bin/bash" , "${path.module}/whatismyip.sh"]
}
resource "aws_security_group_rule" "allow_ssh_from_my_ip" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [format("%s/%s",data.external.whatismyip.result["internet_ip"],32)]
security_group_id = "sg-123456"
}
Make sure to install the jq utility and make whatismyip.sh executable using:
sudo apt-get install jq
chmod 755 whatismyip.sh
Since you are now using an additional provider (the External Data Source), initialize Terraform or OpenTofu using:
terraform init # or: tofu init
Alternative without scripts: the http data source #
The http provider obtains the address without an external script, jq or dig:
data "http" "my_ip" {
url = "https://checkip.amazonaws.com"
}
resource "aws_vpc_security_group_ingress_rule" "ssh_from_my_ip" {
security_group_id = aws_security_group.base.id
ip_protocol = "tcp"
from_port = 22
to_port = 22
cidr_ipv4 = "${chomp(data.http.my_ip.response_body)}/32"
}
Better than opening SSH to a fixed IP address is to use AWS Systems Manager Session Manager, which needs no inbound rules.
See more Terraform and Ansible examples (see also AWS Security Groups):