Browse the Repo

file-type-icon.circleci
file-type-icon_ci
file-type-icon_docs
file-type-iconexamples
file-type-iconmodules
file-type-icon_deprecated
file-type-iconauto-update
file-type-iconaws-auth
file-type-iconaws-config
file-type-iconaws-organizations-config-rules
file-type-iconaws-organizations
file-type-iconcloudtrail
file-type-iconcross-account-iam-roles
file-type-iconcustom-iam-entity
file-type-iconfail2ban
file-type-iconguardduty-multi-region
file-type-iconguardduty-single-region
file-type-iconiam-groups
file-type-iconiam-policies
file-type-iconiam-user-password-policy
file-type-iconiam-users
file-type-iconip-lockdown
file-type-iconREADME.md
file-type-iconinstall.sh
file-type-iconip-lockdown
file-type-iconkms-master-key
file-type-iconntp
file-type-iconos-hardening
file-type-iconsaml-iam-roles
file-type-iconssh-grunt-selinux-policy
file-type-iconssh-grunt
file-type-iconssh-iam
file-type-iconssm-healthchecks-iam-permissions
file-type-icontls-cert-private
file-type-icontest
file-type-icon.editorconfig
file-type-icon.gitignore
file-type-iconCODEOWNERS
file-type-iconLICENSE.txt
file-type-iconREADME.adoc

Browse the Repo

file-type-icon.circleci
file-type-icon_ci
file-type-icon_docs
file-type-iconexamples
file-type-iconmodules
file-type-icon_deprecated
file-type-iconauto-update
file-type-iconaws-auth
file-type-iconaws-config
file-type-iconaws-organizations-config-rules
file-type-iconaws-organizations
file-type-iconcloudtrail
file-type-iconcross-account-iam-roles
file-type-iconcustom-iam-entity
file-type-iconfail2ban
file-type-iconguardduty-multi-region
file-type-iconguardduty-single-region
file-type-iconiam-groups
file-type-iconiam-policies
file-type-iconiam-user-password-policy
file-type-iconiam-users
file-type-iconip-lockdown
file-type-iconREADME.md
file-type-iconinstall.sh
file-type-iconip-lockdown
file-type-iconkms-master-key
file-type-iconntp
file-type-iconos-hardening
file-type-iconsaml-iam-roles
file-type-iconssh-grunt-selinux-policy
file-type-iconssh-grunt
file-type-iconssh-iam
file-type-iconssm-healthchecks-iam-permissions
file-type-icontls-cert-private
file-type-icontest
file-type-icon.editorconfig
file-type-icon.gitignore
file-type-iconCODEOWNERS
file-type-iconLICENSE.txt
file-type-iconREADME.adoc
ip-lockdown

ip-lockdown

Lock down specified outgoing ip addresses on a Linux server such that only specific OS users can access them. Used to protect metadata endpoints.

Preview the Code

mobile file icon

README.md

down

ip-lockdown Module

This module can lock down specified outgoing ip addresses on a Linux server such that only specific OS users can access them. The main motivation for locking down EC2 metadata is as follows:

  1. EC2 metadata gives you the credentials you need to assume any IAM role associated with the EC2 instance, and thereby, get all the permissions available in that IAM role.
  2. Locking down the metadata to, for example, only the root user, makes sure that if a hacker breaks into your server with a privileged user, they cannot get the full power of the IAM role.

This module has been tested specifically with Ubuntu, but will probably work with any Debian distribution that uses iptables.

Example

In the example below we restrict access to ec2-instance-metadata endpoint to the users foo, bar and root. All other users on the instance will be blocked from access.

./ip-lockdown 169.254.169.254 foo bar root

Normally users make a curl call to get metadata like the AWS region or credentials associated with this EC2 Instance's IAM Role. Following the invocation of ip-lockdown, only users foo, bar, and root can query that data.

The complete example of using terraform to deploy a generated AMI into your AWS account and automatically invoke ip-lockdown from the User Data is also available in the examples folder.

Installation

To use this module, you just need to:

  1. Install bash-commons on your servers.
  2. Install the ip-lockdown script on your servers.

The best way to do that is to use the Gruntwork Installer in a Packer template (make sure to replace <BASH_COMMONS_VERSION> and <MODULE_SECURITY_VERSION> below with the latest versions from the bash-commons releases page and module-security releases page, respectively):

gruntwork-install --module-name bash-commons --tag <BASH_COMMONS_VERSION> --repo https://github.com/gruntwork-io/bash-commons
gruntwork-install --module-name ip-lockdown --tag <MODULE_SECURITY_VERSION> --repo https://github.com/gruntwork-io/module-security
Option Description Required Example
IP IP address that will be locked down (outgoing access will be disabled) for all but the users specified in subequent [<USER> ... ]] arguments Required 169.254.169.254
USER Space separated whitelist of users who will be allowed outgoing access to specified ip address Optional root (or any other OS user name)

How do you use this module?

This script will insert the necessary rules to achieve the proper end result of only allowing the specified users to access the locked ips.

  • It will NOT modify your existing rules
  • It will NOT add multiple identical rules if you keep running the script (it is idempotent)
  • It will automatically add rules at the correct rule index if you chose to add more users later or to add more IP addresses later.

General iptables overview

The ip-lockdown script uses iptables under the hood. The iptables application works by defining rules that can then be applied to each outgoing packet. The rules are applied in order (sudo iptables -L line-num to see your current rules as well as their rule-indicies).

In order to block access to a specific IP address for a specific user you need 2 rules.

  1. A rule to ALLOW packets going to YYY owned by user foo
  2. A rule to BLOCK packets going to YYY

The ordering of the rules is important as iptables will go through the rules list until it finds a matching rule. As soon as a matching rule is found none of the subsequent rules are evaluated.

In the above example, reversing those two rules would result in all access to YYY blocked even though there is a subsequent rule to allow foo to access.

Why not use groups?

In an ideal scenario, rather than adding one allow rule per user, we would just create a new canAccessIP group, and add our required users to that group. Then we would just need two iptables rules to manage access.

Unfortunately iptables suffers from the limitation that it will only compare the primary group of the user rather than all of the groups that users belongs to. This limitation is the reason the ip-lockdown script has to create rules per user. As we do not want to modify each user and update their primary user group in case that this causes issues for some other process.

For reference of this limitation see the following:

Questions? Ask away.

We're here to talk about our services, answer any questions, give advice, or just to chat.

Ready to hand off the Gruntwork?