Skip to content

Commit

Permalink
Merge pull request #115 from basti-app/feat-basti/make-bastion-public…
Browse files Browse the repository at this point in the history
…-ip-configurable

feat(many): make bastion public ip address configurable
  • Loading branch information
BohdanPetryshyn authored Sep 27, 2024
2 parents b3b61ca + a8fe998 commit c9e5aa2
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 57 deletions.
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

<!-- The following toc is generated with the Markdown All in One VSCode extension (https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) -->
<!-- omit from toc -->

## Table of contents

- [💡 Why Basti?](#-why-basti)
- [⚙️ How it works](#️-how-it-works)
- [💻 Installation](#-installation)
Expand Down Expand Up @@ -64,7 +66,6 @@

<br/>


## 💡 Why Basti?

With [Basti](https://github.com/basti-app/basti), you can securely connect to RDS, Aurora, Elasticache, or any other AWS resources in private VPC subnets from a local machine or a CI/CD pipeline almost for free!
Expand All @@ -73,7 +74,7 @@ With [Basti](https://github.com/basti-app/basti), you can securely connect to RD

- 🦾 With Session Manager, you need to oversee an EC2 bastion instance for connecting to managed resources such as RDS or Elasticache. Basti handles bastion instance setup, shutdown, and updates for you!

- 💅 Basti provides a convenient way to store and reuse connection configuration across your team.
- 💅 Basti provides a convenient way to store and reuse connection configuration across your team.

- 📶 Basti improves stability of the Session Manager sessions by automatically restarting failed or expired sessions.

Expand Down Expand Up @@ -163,9 +164,9 @@ To connect to a custom target, select the `Custom` option when prompted for a ta
## 🎛️ Advanced initialization options

The `basti init` command has a number of advanced options that can be used to customize the bastion instance and other resources created by Basti.
The `basti init` command has a number of advanced options that can be used to customize the bastion instance and other resources created by Basti.

> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/cli.md#basti-init-command) for the full list of options.
> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/cli.md#basti-init-command) for the full list of options.
### Resource tags

Expand All @@ -192,6 +193,16 @@ Tags with the same name will be overwritten in the order they are specified. Tag

You can specify the EC2 instance type to be used for the bastion instance using the `--bastion-instance-type` option or by entering it in the advanced options section of the interactive mode. The default instance type is `t2.micro`, but it's subject to change in the future.

### Assign public IP address

By default, the bastion instance is created with a public IP address to enable seamless **outbound-only** connection to AWS services from a public VPC subnet. Please, refer to the [AWS documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-prerequisites.html) for more details on the Session Manager requirements.

You can disable the public IP address using the `--bastion-assign-public-ip false` option or in the advanced options section of the interactive mode.

> ☝️ When the public IP address is disabled, you will need to manually ensure that the AWS Session Manager [connectivity requirements](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-prerequisites.html) are met. This can be done with the help of VPC endpoints, NAT gateways, or other means.
> 💡 Disabling public IP address can be useful when setting up the bastion instance in a private subnet.
## 🦾 Automatic mode

Using interactive mode is convenient when you're getting used to Basti. However, in Continuous Integration and Continuous Delivery (CI/CD) pipelines, you will probably want to disable interactivity and pass all the options as command line arguments:
Expand All @@ -212,8 +223,8 @@ wait-on tcp:localhost:your-port
## 📝 Configuration file

When working with multiple connection targets, it becomes convenient to store their configurations
and other Basti settings in a dedicated configuration file. To facilitate this, Basti automatically
searches for the configuration file in the current directory and its parent directories.
and other Basti settings in a dedicated configuration file. To facilitate this, Basti automatically
searches for the configuration file in the current directory and its parent directories.
The supported file names are `.basti.yaml`, `.basti.yml`, and `.basti.json`.

You can quickly start a connection defined in the configuration file by passing its
Expand Down Expand Up @@ -269,7 +280,7 @@ targets:
</details>
> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/configuration-file.md) for the full list of configuration options.
> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/configuration-file.md) for the full list of configuration options.
## 💫 Infrastructure as code (IaC)
Expand Down Expand Up @@ -324,9 +335,9 @@ Minimal policy:
"arn:aws:ec2:<your-region>:<your-account-id>:instance/<your-basti-instance-id>"
],
"Condition": {
"BoolIfExists": {
"ssm:SessionDocumentAccessCheck": "true"
}
"BoolIfExists": {
"ssm:SessionDocumentAccessCheck": "true"
}
}
}
]
Expand All @@ -342,6 +353,7 @@ Since Basti uses IAM for access control, the connection history, along with the
A simple connections history can also be found in the AWS Session Manager history. See [AWS Session Manager documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-view-history.html) for more details.

### Shared configuration

The [Basti configuration file](#basti-configuration-file) file can be shared across your organization, making it easy for all developers to connect to the project's cloud infrastructure. A recommended practice is to store the configuration file in the root of your project's repository. This ensures that the configuration is readily accessible to all team members, enabling quick and seamless connections to the required cloud resources.

## 🔐 Security
Expand Down Expand Up @@ -385,12 +397,14 @@ npm run build
Full Basti build consists of two parts:

1. Compiling Basti TypeScript code. The code has to be compiled after each change.

```sh
npm run build-src
# Or, if you want to automatically recompile on each change:
npm run build-src-watch
```

2. Building non-NodeJS dependencies (AWS session-manger-plugin).
This step is only required after the first checkout or in a rare
case when the dependencies are updated.
Expand Down
58 changes: 25 additions & 33 deletions packages/basti-cdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

<!-- The following toc is generated with the Markdown All in One VSCode extension (https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) -->
<!-- omit from toc -->

## Table of contents

- [Why Basti?](#why-basti)
- [How it works](#how-it-works)
- [Installation](#installation)
Expand Down Expand Up @@ -103,54 +105,44 @@ import { BastiAccessSecurityGroup, BastiInstance } from 'basti-cdk';
Use `BastiInstance` construct to create Basti EC2 instance.

```ts
const bastiInstance = new BastiInstance(
stack,
'BastiInstance',
{
vpc,

// Optional. Randomly generated if omitted.
// Used to name the EC2 instance and other resources.
// The resulting name will be "basti-instance-my-bastion"
bastiId: 'my-bastion'
}
);
const bastiInstance = new BastiInstance(stack, 'BastiInstance', {
vpc,

// Optional. Randomly generated if omitted.
// Used to name the EC2 instance and other resources.
// The resulting name will be "basti-instance-my-bastion"
bastiId: 'my-bastion',
});
```

### Allow connection to target

Use `BastiAccessSecurityGroup` construct to create a security group for your target. This security group will allow the Basti instance to connect to the target.
Use `BastiAccessSecurityGroup` construct to create a security group for your target. This security group will allow the Basti instance to connect to the target.

```ts
// Create a security group for your target
const bastiAccessSecurityGroup = new BastiAccessSecurityGroup(
stack,
'BastiAccessSecurityGroup',
'BastiAccessSecurityGroup',
{
vpc,

// Optional. Randomly generated if omitted.
// Used to name the security group and other resources.
// The resulting name will be "basti-access-my-target"
bastiId: 'my-target'
bastiId: 'my-target',
}
);

// Create the target
const rdsInstance = new aws_rds.DatabaseInstance(
stack,
'RdsInstance',
{
// Unrelated properties are omitted for brevity
const rdsInstance = new aws_rds.DatabaseInstance(stack, 'RdsInstance', {
// Unrelated properties are omitted for brevity

vpc,
port: 5432,
vpc,
port: 5432,

securityGroups: [
bastiAccessSecurityGroup
]
}
);
securityGroups: [bastiAccessSecurityGroup],
});

// Allow the Basti instance to connect to the target on the specified port
bastiAccessSecurityGroup.allowBastiInstanceConnection(
Expand All @@ -176,15 +168,15 @@ When sharing a Basti instance across stacks, you can just pass it as a property
```ts
// Most likely, the VPC was created separately as well
const vpc = aws_ec2.Vpc.fromLookup(stack, 'Vpc', {
vpcName: 'existing-vpc-id',
vpcName: 'existing-vpc-id',
});

const bastiInstance = BastiInstance.fromBastiId(
this,
'BastiInstance',
// The BastiID of the Basti instance you want to import
'existing-basti-id',
vpc
this,
'BastiInstance',
// The BastiID of the Basti instance you want to import
'existing-basti-id',
vpc
);

// bastiInstance can now be used to allow access to a connection target
Expand Down
7 changes: 7 additions & 0 deletions packages/basti-cdk/src/basti-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ export interface BastiInstanceProps {
* @default Latest Amazon Linux 2 - Kernel 5.10
*/
readonly machineImage?: aws_ec2.IMachineImage;

/**
* (Optional) Whether to assign a public IP address to the bastion instance.
* If not specified, falls back to the default behavior of the VPC.
*/
readonly assignPublicIp?: boolean;
}

export interface IBastiInstance {
Expand Down Expand Up @@ -170,6 +176,7 @@ export class BastiInstance extends Construct implements IBastiInstance {
instanceName: `${BASTION_INSTANCE_NAME_PREFIX}-${this.bastiId}`,
machineImage: props.machineImage ?? defaultMachineImage,
instanceType: props.instanceType ?? defaultInstanceType,
associatePublicIpAddress: props.assignPublicIp,
role: this.role,
securityGroup: this.securityGroup,
requireImdsv2: true,
Expand Down
34 changes: 24 additions & 10 deletions packages/basti/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

<!-- The following toc is generated with the Markdown All in One VSCode extension (https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) -->
<!-- omit from toc -->

## Table of contents

- [💡 Why Basti?](#-why-basti)
- [⚙️ How it works](#️-how-it-works)
- [💻 Installation](#-installation)
Expand Down Expand Up @@ -70,7 +72,6 @@

<br/>


## 💡 Why Basti?

With [Basti](https://github.com/basti-app/basti), you can securely connect to RDS, Aurora, Elasticache, or any other AWS resources in private VPC subnets from a local machine or a CI/CD pipeline almost for free!
Expand All @@ -79,7 +80,7 @@ With [Basti](https://github.com/basti-app/basti), you can securely connect to RD

- 🦾 With Session Manager, you need to oversee an EC2 bastion instance for connecting to managed resources such as RDS or Elasticache. Basti handles bastion instance setup, shutdown, and updates for you!

- 💅 Basti provides a convenient way to store and reuse connection configuration across your team.
- 💅 Basti provides a convenient way to store and reuse connection configuration across your team.

- 📶 Basti improves stability of the Session Manager sessions by automatically restarting failed or expired sessions.

Expand Down Expand Up @@ -169,9 +170,9 @@ To connect to a custom target, select the `Custom` option when prompted for a ta
## 🎛️ Advanced initialization options

The `basti init` command has a number of advanced options that can be used to customize the bastion instance and other resources created by Basti.
The `basti init` command has a number of advanced options that can be used to customize the bastion instance and other resources created by Basti.

> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/cli.md#basti-init-command) for the full list of options.
> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/cli.md#basti-init-command) for the full list of options.
### Resource tags

Expand All @@ -198,6 +199,16 @@ Tags with the same name will be overwritten in the order they are specified. Tag

You can specify the EC2 instance type to be used for the bastion instance using the `--bastion-instance-type` option or by entering it in the advanced options section of the interactive mode. The default instance type is `t2.micro`, but it's subject to change in the future.

### Assign public IP address

By default, the bastion instance is created with a public IP address to enable seamless **outbound-only** connection to AWS services from a public VPC subnet. Please, refer to the [AWS documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-prerequisites.html) for more details on the Session Manager requirements.

You can disable the public IP address using the `--bastion-assign-public-ip false` option or in the advanced options section of the interactive mode.

> ☝️ When the public IP address is disabled, you will need to manually ensure that the AWS Session Manager [connectivity requirements](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-prerequisites.html) are met. This can be done with the help of VPC endpoints, NAT gateways, or other means.
> 💡 Disabling public IP address can be useful when setting up the bastion instance in a private subnet.
## 🦾 Automatic mode

Using interactive mode is convenient when you're getting used to Basti. However, in Continuous Integration and Continuous Delivery (CI/CD) pipelines, you will probably want to disable interactivity and pass all the options as command line arguments:
Expand All @@ -218,8 +229,8 @@ wait-on tcp:localhost:your-port
## 📝 Configuration file

When working with multiple connection targets, it becomes convenient to store their configurations
and other Basti settings in a dedicated configuration file. To facilitate this, Basti automatically
searches for the configuration file in the current directory and its parent directories.
and other Basti settings in a dedicated configuration file. To facilitate this, Basti automatically
searches for the configuration file in the current directory and its parent directories.
The supported file names are `.basti.yaml`, `.basti.yml`, and `.basti.json`.

You can quickly start a connection defined in the configuration file by passing its
Expand Down Expand Up @@ -275,7 +286,7 @@ targets:
</details>
> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/configuration-file.md) for the full list of configuration options.
> 💡 Please, refer to the [reference documentation](https://github.com/basti-app/basti/blob/main/docs/reference/configuration-file.md) for the full list of configuration options.
## 💫 Infrastructure as code (IaC)
Expand Down Expand Up @@ -330,9 +341,9 @@ Minimal policy:
"arn:aws:ec2:<your-region>:<your-account-id>:instance/<your-basti-instance-id>"
],
"Condition": {
"BoolIfExists": {
"ssm:SessionDocumentAccessCheck": "true"
}
"BoolIfExists": {
"ssm:SessionDocumentAccessCheck": "true"
}
}
}
]
Expand All @@ -348,6 +359,7 @@ Since Basti uses IAM for access control, the connection history, along with the
A simple connections history can also be found in the AWS Session Manager history. See [AWS Session Manager documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-view-history.html) for more details.

### Shared configuration

The [Basti configuration file](#basti-configuration-file) file can be shared across your organization, making it easy for all developers to connect to the project's cloud infrastructure. A recommended practice is to store the configuration file in the root of your project's repository. This ensures that the configuration is readily accessible to all team members, enabling quick and seamless connections to the required cloud resources.

## 🔐 Security
Expand Down Expand Up @@ -391,12 +403,14 @@ npm run build
Full Basti build consists of two parts:

1. Compiling Basti TypeScript code. The code has to be compiled after each change.

```sh
npm run build-src
# Or, if you want to automatically recompile on each change:
npm run build-src-watch
```

2. Building non-NodeJS dependencies (AWS session-manger-plugin).
This step is only required after the first checkout or in a rare
case when the dependencies are updated.
Expand Down
1 change: 1 addition & 0 deletions packages/basti/src/bastion/bastion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export const BASTION_INSTANCE_UPDATING_TAG_NAME = 'basti:updating';
export const BASTION_INSTANCE_UPDATED_TAG_NAME = 'basti:updated';

export const BASTION_INSTANCE_DEFAULT_INSTANCE_TYPE = 't2.micro';
export const BASTION_INSTANCE_DEFAULT_ASSIGN_PUBLIC_IP = true;
Loading

0 comments on commit c9e5aa2

Please sign in to comment.