Skip to content

Commit

Permalink
chore: Update bastion configuration and enable IPv4 forwarding
Browse files Browse the repository at this point in the history
  • Loading branch information
ulises-jeremias committed Jul 8, 2024
1 parent 4d56989 commit 8816f4a
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 81 deletions.
82 changes: 11 additions & 71 deletions live/core-networking/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

```sh
# Switch to another workspace or create it if it doesn't exist
terraform workspace select -or-create prod
terraform workspace select -or-create sandbox
```
## Deploy
Expand All @@ -75,15 +75,15 @@
Review and verify the deployment plan:
```sh
terraform plan -var-file ./configs/prod.tfvars -out prod.tfplan
terraform plan -var-file ./configs/sandbox.tfvars -out sandbox.tfplan
```
2. **Execute the Plan:**
Apply the planned configuration to provision the infrastructure:
```sh
terraform apply "prod.tfplan"
terraform apply "sandbox.tfplan"
```
## Post Deployment Steps
Expand All @@ -105,90 +105,30 @@ echo "VPC ID: $vpc_id"
### Connecting to the Bastion Host Using Session Manager
AWS Session Manager provides secure and auditable instance management without needing to open inbound ports, manage SSH keys, or use bastion hosts.
AWS Session Manager provides secure and auditable instance management without needing to open inbound ports, manage SSH keys, or use bastion hosts. To connect to the bastion host using Session Manager, follow these steps:
#### Prerequisites
#### Gather Information
Ensure the following prerequisites are met:
1. **SSM Agent**: Ensure the SSM agent is installed and running on your instance. For Amazon Linux, the SSM agent is pre-installed.
2. **IAM Role**: The instance must have an IAM role attached with the necessary permissions for AWS Systems Manager. Typically, this includes the `AmazonSSMManagedInstanceCore` policy.
3. **Session Manager Plugin**: Ensure the Session Manager Plugin is installed on your local machine. Check the [AWS Session Manager Plugin Installation Guide](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) for more information.
#### Obtain Required Information
First, gather the necessary information:
- Bastion Instance ID
You can retrieve this value using Terraform:
Get the Bastion Instance ID from the Terraform output. You can retrieve this value using Terraform:
```bash
bastion_instance_id=$(terraform output -json | jq -r '.bastion_instance_id.value')
```
#### Start a Session with the Bastion Host
Use AWS Session Manager to start a session with your instance:
```bash
aws ssm start-session --target "$bastion_instance_id"
```
This command will open a new session in your terminal, allowing you to interact with your instance securely.
### Additional Useful Commands
#### List Active Sessions
To list all active sessions:
```bash
aws ssm describe-sessions --state "Active"
```
#### Terminate a Session

To terminate a specific session, you need the session ID. First, list the active sessions to get the session ID:
```bash
aws ssm describe-sessions --state "Active"
```
Then terminate the session using the session ID:
```bash
aws ssm terminate-session --session-id <session-id>
```
### Example Script for Complete Workflow
Here's a complete example script to retrieve the VPC ID, Bastion instance ID, and start a Session Manager session:
```bash
# Retrieve VPC ID from Parameter Store
vpc_id_parameter_name=$(terraform output -json | jq -r '.ssm_parameter_vpc_id.value')
vpc_id=$(aws ssm get-parameter --name "$vpc_id_parameter_name" --query 'Parameter.Value' --output text)
echo "VPC ID: $vpc_id"
# Retrieve Bastion instance ID
bastion_instance_id=$(terraform output -json | jq -r '.bastion_instance_id.value')
echo "Bastion Instance ID: $bastion_instance_id"
# Start Session Manager session with Bastion Host
aws ssm start-session --target "$bastion_instance_id"
```
This approach leverages AWS Session Manager for secure and easy access to your instances, removing the need for SSH keys and open inbound ports. If you have any further questions or need additional assistance, please let me know!
#### Follow the Connection Steps
You can check the Bastion Host Module documentation for detailed steps on connecting to the bastion host using Session Manager: [Connect to Bastion Host Using Session Manager](../../modules/bastion/README.md#connecting-to-the-bastion-host-using-session-manager).
## Destroy
💣 **NOTE:** In this example, we are using the `prod` environment and the `us-west-2` region. Modify these values according to your environment and region.
💣 **NOTE:** In this example, we are using the `sandbox` environment and the `us-west-2` region. Modify these values according to your environment and region.
To destroy the infrastructure, run the following command:
```sh
terraform destroy -var-file ./configs/prod.tfvars
terraform destroy -var-file ./configs/sandbox.tfvars
```
## Module Documentation
Expand Down
192 changes: 182 additions & 10 deletions modules/bastion/README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
# Bastion Host
# Bastion Host Terraform Module

Terraform module to bootstrap a bastion host in AWS using EC2.

## Summary

A bastion host, sometimes called a `jump box`, is a server that provides a single point of access from an external network to resources located in a private network. This module uses AWS Systems Manager Session Manager and Amazon EC2 Instance Connect to securely connect to an Amazon EC2 bastion host without exposing any inbound ports or managing long-lived SSH keys.

## Usage

```hcl
module "bastion" {
source = "../../modules/bastion"
name = "example-bastion"
vpc_id = "vpc-1234567890"
subnets = ["subnet-1234567890", "subnet-0987654321"]
associate_public_ip_address = true
associate_elastic_ip_address = true
}
```

## Module Documentation

The module documentation is generated with [terraform-docs](https://github.com/terraform-docs/terraform-docs) by running `terraform-docs md . > ./docs/MODULE.md` from the module directory.

You can also view the latest version of the module documentation [here](./docs/MODULE.md).

## EC2 Instance Provisioning

The created EC2 instance is provisioned using [cloud-init](https://cloudinit.readthedocs.io/en/latest/). The following steps are performed:
Expand All @@ -32,3 +27,180 @@ The created EC2 instance is provisioned using [cloud-init](https://cloudinit.rea
- Setup SSH access for the specified key pair
- Setup a user account for the specified key pair
- Setup a user account for the specified IAM instance profile
- Install AWS Session Manager Agent

## Connecting to the Bastion Host Using Session Manager

### Prerequisites

Ensure the following prerequisites are met:

1. **Session Manager Plugin**: Ensure the Session Manager Plugin is installed on your local machine. Check the [AWS Session Manager Plugin Installation Guide](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) for more information.

### Setup Local Environment

1. **Install tools**

Follow [Prerequisites](#prerequisites) section to install AWS CLI and Session Manager plugin.

2. **Configure SSH connection**

Follow [the documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html#ssh-connections-enable) to update the SSH configuration file to allow SSH connections through Session Manager. It allows running a proxy command that starts a Session Manager session and transfer all data through opened connection.

3. **Generate SSH keys**

Generate local SSH private and public keys. For example, you can use following command:

```shell
ssh-keygen -t rsa -f my_key
```

It will generate private and public SSH key pair which are going to be used to connect to bastion host.
It is recommended to provide password to protect access to keys and store keys in secure location.

### Connect to Bastion Host

1. **Assume IAM Role**

Assume an IAM role that has permissions to authenticate, authorize, and connect to the EC2 instance.

2. **Get instance id**

In order to connect to deployed bastion host you will need to obtain EC2 instance id. There are multiple ways you can do
that. For example you can get it using AWS console by navigating
to [EC2 dashboard](https://eu-central-1.console.aws.amazon.com/ec2/home) or through AWS CLI using:

```shell
aws ec2 describe-instances
```

To further filter results you can use following command:

```shell
aws ec2 describe-instances --filters 'Name=tag:Name,Values=$BASTION_HOST_TAG' --output text --query 'Reservations[*].Instances[*].InstanceId' --output text
```

Replace `$BASTION_HOST_TAG` with tag used to mark bastion host.
Copy obtained EC2 instance id for later use.

3. **Send SSH keys**

In order to connect to the bastion host we first have to send SSH key to the host using EC2 Instance Connect.
Use following command replacing `$INSTANCE_ID` with EC2 instance id obtained in previous step and `$PUBLIC_KEY_FILE`
with path to your public key file (for example: `my_key.pub`).

**Be sure to use public key and NOT private key.**

```shell
aws ec2-instance-connect send-ssh-public-key --instance-id $INSTANCE_ID --instance-os-user ubuntu --ssh-public-key file://$PUBLIC_KEY_FILE
```

You should receive message indicated successful upload of key. You have just uploaded temporary SSH key
to [EC2 instance metadata](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) where it’s
going to remain for 60 seconds. After 60 seconds SSH key gets removed automatically, and you won’t be able to use it to
connect to the instance. You will see “Permission denied” error if you try. If this happens you can resend the key using
the same command.

This means that you have 60 seconds to initialize SSH connection after you upload keys. Follow next step to do so.

4. **Connect using SSH through Sessions Manager**

In this last step you will connect to your bastion host using SSH. Use following command replacing
`$PRIVATE_KEY_FILE` with path to your private key (for example: my_key) and `$INSTANCE_ID` with EC2 instance id obtained
in previous steps.

```shell
ssh -i $PRIVATE_KEY_FILE ubuntu@$INSTANCE_ID
```

Confirm connection by typing yes. It will open SSH connection using previously configured Session Manager.

You’re in!

### Additional Useful Commands

#### List Active Sessions

To list all active sessions:

```bash
aws ssm describe-sessions --state "Active"
```

#### Terminate a Session

To terminate a specific session, you need the session ID. First, list the active sessions to get the session ID:

```bash
aws ssm describe-sessions --state "Active"
```

Then terminate the session using the session ID:

```bash
aws ssm terminate-session --session-id <session-id>
```

### Example Script for Complete Workflow

Here's a complete example script to retrieve the Bastion instance ID, push the SSH public key, and start a Session Manager session:

```bash
# Asume el rol IAM necesario
assume_role_output=$(aws sts assume-role --role-arn arn:aws:iam::<account-id>:role/<role-name> --role-session-name AWSCLI-Session)

# Exporta las credenciales temporales del rol asumido
export AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' <<< "$assume_role_output")
export AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' <<< "$assume_role_output")
export AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' <<< "$assume_role_output")

# Retrieve Bastion instance ID
bastion_instance_id=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=<BASTION_HOST_TAG>" --query "Reservations[*].Instances[*].InstanceId" --output text)
echo "Bastion Instance ID: $bastion_instance_id"

# Push SSH Public Key
ssh_public_key="your-public-key"
aws ec2-instance-connect send-ssh-public-key --instance-id "$bastion_instance_id" --instance-os-user ubuntu --ssh-public-key file://$ssh_public_key

# Start Session Manager session with Bastion Host
aws ssm start-session --target "$bastion_instance_id"

# Connect using SSH through Session Manager
ssh -i /path/to/your/private/key ubuntu@$bastion_instance_id
```

### Optional Steps

#### Use Other SSH Options to Open Connection

It is possible to use different options to open connection to bastion host. For example you can use -D 8888 option to open SSH connection with a local “dynamic” application-level port forwarding through 8888 port. See [this link](https://explainshell.com/explain?cmd=ssh+-i+%24PRIVATE_KEY_FILE+-D+8888+ubuntu%40%24INSTANCE_ID) for detailed explanation.

```shell
ssh -i $PRIVATE_KEY_FILE -D 8888 ubuntu@$INSTANCE_ID
```

This kind of connection opens a SOCKS proxy you can use for example to forward traffic from your local browser through bastion host. Refer to man pages of ssh command to see all options.

### Troubleshooting

Sometimes you might experience `TargetNotConnected` error when trying to connect to the bastion host.

Solution:

1. Follow [Reboot your instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-reboot.html) AWS documentation to reboot deployed bastion host.
2. Follow [Connect to the bastion host](#connect-to-bastion-host) section of this document and try to connect again.

## Additional Resources

- [AWS Systems Manager Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html)
- [Amazon EC2 Instance Connect](<https://docs>

.aws.amazon.com/AWSEC2/latest/UserGuide/Connect-using-EC2-Instance-Connect.html)

- [Enabling SSH connections through Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html#ssh-connections-enable)

## Module Documentation

The module documentation is generated with [terraform-docs](https://github.com/terraform-docs/terraform-docs) by running `terraform-docs md . > ./docs/MODULE.md` from the module directory.

You can also view the latest version of the module documentation [here](./docs/MODULE.md).

0 comments on commit 8816f4a

Please sign in to comment.