I rent a little house on a huge ranch a touch over an hour northwest of Austin, TX. I also work as a software engineer for Quansight primarily utilizing Python. The beauty of this setup is the hybrid techy/rural lifestyle I enjoy. And the baby bison. The downside, the internet.
(photo from my kitchen window)
My only source of internet is via a cell phone hotspot. Luckily, modern cell phone plans offer just enough data to make this possible-so long as you’re willing to sacrifice Netflix binges. One side effect of using a cell phone hotspot is a constantly changing public IP address. For most folks, this isn’t a problem. When working on Amazon EC2 instances that utilize IP address whitelists to secure SSH traffic, it’s a pain. Each day (and randomly throughout) my IP address will change. Every time it changed I would perform this ritual:
Login to AWS console
Open the corresponding security group
Lookup my IP on Google
Add the new IP
This got old fast.
After living with this extremely manual process for several months, I was in a meeting with a DevOps engineer who said: “Whenever I have to do something twice, I automate it.” This was the motivation I needed to rid myself of a repetitive task. The first tool that came to mind was AWS CLI. I was very familiar with this command line tool after using it on several different projects. I considered a Bash script, but quickly remembered how little fun I had last time I created a Bash script. There had to be a better way without having to deal with a new language for a single task.
Enter xonsh shell
What is Xonsh? In a word, slick. As described by the cleverly named website, xon.sh, xonsh is: “A Python-powered, cross-platform, Unix-gazing shell language and command prompt.” In several other words, it means I can do stuff in the terminal with modified Python syntax that previously would have required me to learn more Bash. In a pun, I could search the ocean and not find a better tool.
Xonsh allows the running of terminal and Python commands simultaneously. Xonsh will attempt to detect whether a command needs to be interpreted as a subprocess or python command. More complicated commands require these modes to be explicitly stated. Python mode can be explictly entered with the @() operator, while subprocess mode can be explicitly entered with the $() operator
For example, this line will capture and format my public IP and save it to the variable myip:
myip = $(curl https://checkip.amazonaws.com).strip('\n')+'/32'
As seen, the output from the terminal command curl https://checkip.amazonaws.com can be used right alongside python code. I can then use this variable in future commands:
security_group = 'sg-007' region = 'eu-west-2' myip = $(curl https://checkip.amazonaws.com).strip('\n')+'/32' $(aws ec2 authorize-security-group-ingress --group-id @(security_group) --protocol tcp --port 22 --region @(region) --cidr @(myip))
My IP address is whitelisted!
Because I work with multiple AWS accounts, I also need to specify the AWS_PROFILE environment variable so it pulls the correct credentials from my ~/.aws/config file. This can be done by prepending the environment variable I want to set with $. I add this all to a file with the Xonsh shebang #!/usr/bin/env xonsh, and voila, automation is born:
#!/usr/bin/env xonsh $AWS_PROFILE = 'MI6' security_group = 'sg-007' region = 'eu-west-2' myip = $(curl https://checkip.amazonaws.com).strip('\n')+'/32' $(aws ec2 authorize-security-group-ingress --group-id @(security_group) --protocol tcp --port 22 --region @(region) --cidr @(myip))
Finally, I save the file as whitelist.xsh and add alias whitelist='xonsh ~/scripts/whitelist.xsh' to my .bashrc. I can now whitelist my IP with a single word in my terminal: whitelist.
I’m happy, the security group is happy, and I assume the baby bison is happy as well.