{"id":13602404,"url":"https://github.com/basti-app/basti","last_synced_at":"2026-01-15T22:18:25.905Z","repository":{"id":56507554,"uuid":"503057799","full_name":"basti-app/basti","owner":"basti-app","description":"✨ Securely connect to RDS, Elasticache, and other AWS resources in VPCs with no idle cost","archived":false,"fork":false,"pushed_at":"2025-11-22T09:53:04.000Z","size":3006,"stargazers_count":405,"open_issues_count":19,"forks_count":23,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-13T04:09:55.666Z","etag":null,"topics":["automation","aws","cdk","cicd","cli","cost-optimization","hacktoberfest","networking","nodejs","rds","security","vpc"],"latest_commit_sha":null,"homepage":"https://www.basti.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/basti-app.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-06-13T17:46:09.000Z","updated_at":"2026-01-07T17:32:39.000Z","dependencies_parsed_at":"2024-09-08T04:21:17.550Z","dependency_job_id":"3ee70649-f2f3-4b5b-b91b-1cc570b265d7","html_url":"https://github.com/basti-app/basti","commit_stats":{"total_commits":311,"total_committers":10,"mean_commits":31.1,"dds":"0.11897106109324762","last_synced_commit":"607d32239250ded5e888307d64cb3e491e43cdd6"},"previous_names":["basti-app/basti","bohdanpetryshyn/basti"],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/basti-app/basti","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basti-app%2Fbasti","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basti-app%2Fbasti/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basti-app%2Fbasti/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basti-app%2Fbasti/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/basti-app","download_url":"https://codeload.github.com/basti-app/basti/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basti-app%2Fbasti/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28472625,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T22:13:38.078Z","status":"ssl_error","status_checked_at":"2026-01-15T22:12:11.737Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","aws","cdk","cicd","cli","cost-optimization","hacktoberfest","networking","nodejs","rds","security","vpc"],"created_at":"2024-08-01T18:01:22.247Z","updated_at":"2026-01-15T22:18:25.889Z","avatar_url":"https://github.com/basti-app.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","cli"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eBasti\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/basti\"\u003e\n    \u003cimg alt=\"NPM Package\" src=\"https://img.shields.io/npm/v/basti?color=blue\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/basti\"\u003e\n    \u003cimg alt=\"NPM\" src=\"https://img.shields.io/npm/dt/basti\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/basti-app/basti/blob/main/LICENSE\"\u003e\n    \u003cimg alt=\"GitHub\" src=\"https://img.shields.io/github/license/basti-app/basti\"\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/basti-app/basti\"\u003eBasti\u003c/a\u003e \u003cem\u003e(from \u003ca href=\"https://en.wikipedia.org/wiki/Bastion_host\"\u003e\u003cstrong\u003eBasti\u003c/strong\u003eon Host\u003c/a\u003e)\u003c/em\u003e is a CLI tool for securely accessing your DB instances and other AWS resources in private networks at almost no cost. \n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  💵 \u003cem\u003eNo idle costs.\u003c/em\u003e  🔑 \u003cem\u003eNo SSH keys.\u003c/em\u003e 🔒 \u003cem\u003eFully IAM-driven.\u003c/em\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg alt=\"Demo\" src=\"https://user-images.githubusercontent.com/45905756/211385579-3ac54ad5-7c90-4b68-9b22-239f4b26ad61.gif\"\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003c!-- The following toc is generated with the Markdown All in One VSCode extension (https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) --\u003e\n\n\u003c!-- omit from toc --\u003e\n## Table of contents\n\n- [💡 Why Basti?](#-why-basti)\n- [⚙️ How it works](#️-how-it-works)\n- [💻 Installation](#-installation)\n- [🏄 Basic usage](#-basic-usage)\n  - [☝️ Initialize connection target](#️-initialize-connection-target)\n  - [✌️ Connect to the target](#️-connect-to-the-target)\n  - [🎉 Use the target on _localhost_](#-use-the-target-on-localhost)\n  - [Cleanup (optional)](#cleanup-optional)\n- [🧶 Reference documentation](#-reference-documentation)\n- [💠 Custom connection targets](#-custom-connection-targets)\n- [🎛️ Advanced initialization options](#️-advanced-initialization-options)\n  - [Resource tags](#resource-tags)\n  - [Bastion instance type](#bastion-instance-type)\n  - [Assign public IP address](#assign-public-ip-address)\n- [🦾 Automatic mode](#-automatic-mode)\n- [📝 Configuration file](#-configuration-file)\n- [💫 Infrastructure as code (IaC)](#-infrastructure-as-code-iac)\n- [🏢 Basti in teams and organizations](#-basti-in-teams-and-organizations)\n  - [Minimal IAM permissions](#minimal-iam-permissions)\n  - [Usage audit](#usage-audit)\n  - [Shared configuration](#shared-configuration)\n- [🔐 Security](#-security)\n  - [Network](#network)\n  - [Access control](#access-control)\n  - [Software](#software)\n- [❤️ Development](#️-development)\n  - [Build](#build)\n  - [Run](#run)\n  - [Test](#test)\n- [License](#license)\n\n\u003cbr/\u003e\n\n## 💡 Why Basti?\n\nWith [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!\n\n[AWS Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html) is a fantastic tool! But Basti makes it even better:\n\n- 🦾 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!\n\n- 💅 Basti provides a convenient way to store and reuse connection configuration across your team.\n\n- 📶 Basti improves stability of the Session Manager sessions by automatically restarting failed or expired sessions.\n\n## ⚙️ How it works\n\n- 🏰 Basti sets up a so called _bastion EC2 instance_ in the connection target's VPC.\n\n- 🧑‍💻 The bastion instance is used with [AWS Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html) port forwarding capability to make the target available on your _localhost_.\n\n- 💵 Basti takes care of keeping the bastion instance stopped when it's not used to make the solution cost as low as **≈ 0.01 USD** per hour of connection plus **≈ 0.80 USD** per month of maintaining the instance in a stopped state.\n\n- 🔒 [Security](#security) completely relies on AWS Session Manager and IAM policies. The bastion instance is not accessible from the Internet and no SSH keys are used.\n\n## 💻 Installation\n\nUsing homebrew\n\n```sh\nbrew install basti\n```\n\nUsing npm\n\n```sh\nnpm install --global basti\n```\n\nOther, NodeJS-independent, installation options are coming soon!\n\n## 🏄 Basic usage\n\nBasti uses AWS SDK and relies on credentials to be configured in your system. You can use any of [the methods](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html) supported by AWS SDK to configure credentials.\n\n\u003e 💡 You can expect Basti to work if you can use AWS CLI in your terminal.\n\n### ☝️ Initialize connection target\n\nFirst, initialize your connection target. It could be an RDS instance, an Elasticache cluster or any other target residing in a VPC. The following command will set up all the infrastructure required to start a connection. _You only need to do this once_.\n\n```sh\nbasti init\n```\n\nYou will be prompted for a target to initialize and a **public** VPC subnet to create the bastion EC2 instance in.\n\n### ✌️ Connect to the target\n\nNow, you can start the connection. This command will establish a secure port forwarding session and make the target available on your _localhost_.\n\n```sh\nbasti connect\n```\n\nYou will be prompted for the target to connect to as well as the local port to forward the connection to.\n\n### 🎉 Use the target on _localhost_\n\nFinally, you can use the target same way as it was running on your _localhost_ and port you specified in the previous step.\n\n```sh\npsql -h localhost -p 5432\n```\n\n\u003e 💡 _psql_, the PostgreSQL client, is used as an example here. Basti can be used to connect to any type of database or other services as long as the communication is done over TCP.\n\n### Cleanup (optional)\n\nYou can remove all the resources created by Basti in you AWS account.\n\n```sh\nbasti cleanup\n```\n\nThe list of resources will be displayed and you will be prompted to confirm the cleanup.\n\n## 🧶 Reference documentation\n\nPlease, refer to the [reference documentation](https://github.com/basti-app/basti/tree/main/docs/reference) for the full description of Basti CLI options and the configuration file.\n\n## 💠 Custom connection targets\n\nBasti provides first class support for RDS instances, Aurora clusters, and Elasticache clusters. However, you can use Basti to connect to any other target in your AWS VPC (e.g. DocumentDB instance, EC2 instance, etc.).\n\nTo connect to a custom target, select the `Custom` option when prompted for a target to initialize or connect to. You will be prompted for the target's VPC, IP address and port.\n\n\u003e 🤝 Feel free to open an issue or a pull request if you want to extend the list of natively supported targets\n\n## 🎛️ Advanced initialization options\n\nThe `basti init` command has a number of advanced options that can be used to customize the bastion instance and other resources created by Basti.\n\n\u003e 💡 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.\n\n### Resource tags\n\nYou can specify tags to be applied to the bastion instance and other resources created by Basti. This can be done in three ways:\n\n1. By entering the tags in the advanced options section of the interactive mode.\n2. By passing the `--tag` option. This option accepts tag name and value separated by an equal sign. For example, `--tag Project=my-project` This option can be used multiple times to specify multiple tags.\n3. By passing the `--tags-file` option. This option accepts a path to a JSON file with tags. The option can be used multiple times to specify multiple files.\n\nExample of a tags file:\n\n```json\n{\n  \"Project\": \"my-project\",\n  \"Environment\": \"production\"\n}\n```\n\nTags with the same name will be overwritten in the order they are specified. Tags specified with the `--tag` option will always overwrite tags specified in the tags file.\n\n\u003e 💡 If your tags contain special characters, it might be easier to use interactive mode or the `--tags-file` command than escaping the characters in the `--tag` option.\n\n### Bastion instance type\n\nYou 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.\n\n### Assign public IP address\n\nBy 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.\n\nYou can disable the public IP address using the `--bastion-assign-public-ip false` option or in the advanced options section of the interactive mode.\n\n\u003e ☝️ 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.\n\n\u003e 💡 Disabling public IP address can be useful when setting up the bastion instance in a private subnet.\n\n## 🦾 Automatic mode\n\nUsing 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:\n\n```sh\nbasti connect --rds-instance your-instance-id --local-port your-port\n```\n\nUse `basti \u003ccommand\u003e --help` to see all the available options for `basti connect` and other commands.\n\nTo continue executing the script after the connection is established, you can use Basti in conjunction with the [wait-on utility](https://www.npmjs.com/package/wait-on) and the `\u0026` shell operator:\n\n```sh\nbasti connect --rds-instance your-instance-id --local-port your-port \u0026\nwait-on tcp:localhost:your-port\n```\n\n## 📝 Configuration file\n\nWhen working with multiple connection targets, it becomes convenient to store their configurations\nand other Basti settings in a dedicated configuration file. To facilitate this, Basti automatically\nsearches for the configuration file in the current directory and its parent directories.\nThe supported file names are `.basti.yaml`, `.basti.yml`, and `.basti.json`.\n\nYou can quickly start a connection defined in the configuration file by passing its\nname to the `basti connect` command:\n\n```sh\nbasti connect your-connection\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003e Configuration file example \u003c/b\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nThis example uses YAML format. The same configuration can be written in JSON.\n\n```yaml\n# - Connections are used with the `basti connect \u003cconnection\u003e` command\n# - Targets' fields are the same as the options for the `basti connect` command\nconnections:\n  database-dev:\n    target:\n      rdsInstance: my-dev-database\n      awsProfile: dev\n    localPort: 5432\n\n  database-prod:\n    target:\n      rdsInstance: my-prod-database\n      awsProfile: prod\n    localPort: 5432\n\n  # Default AWS profile and region are used if not specified in the target\n  redis-cache-dev:\n    target:\n      elasticacheRedisCluster: my-dev-cache\n    localPort: 6379\n\n  # Same target but with different local port\n  custom-target-local:\n    target: custom-target\n    localPort: 4646\n\n# Targets can be extracted and reused in multiple connections\n# with different local ports\ntargets:\n  custom-target:\n    customTargetVpc: vpc-1234567890\n    customTargetHost: 10.0.1.1\n    customTargetPort: 4646\n    awsProfile: prod\n    awsRegion: us-east-1\n```\n\n\u003c/details\u003e\n\n\u003e 💡 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.\n\n## 💫 Infrastructure as code (IaC)\n\nIntroducing, [Basti CDK](https://github.com/basti-app/basti/tree/main/packages/basti-cdk), an [AWS CDK](https://aws.amazon.com/cdk/) construct library that allows you to integrate Basti with your existing CDK-managed infrastructure.\n\nFeel free to open an issue if you want to see Basti in Terraform or other IaC tools. Contributions are welcome 🤗\n\n## 🏢 Basti in teams and organizations\n\nBasti was designed with organizational usage patterns in mind. The bastion instance and other infrastructure created by Basti is reused across all the users in your organization.\n\n### Minimal IAM permissions\n\nBasti commands require different sets of IAM permissions. `basti init` needs broad permissions to set up all the infrastructure required to start a connection. `basti connect`, on the other hand, requires only minimal permissions to start a connection. This means that the AWS account administrator can run the `basti init` command once and then grant the minimal permissions to the IAM users who need to start connections.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003e Minimal IAM policy for connection \u003c/b\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\nThe following command is optimized for minimal permissions required to start a connection. It doesn't need to retrieve the target information as it's passed as command line arguments.\n\n```sh\nbasti connect --custom-target-vpc your-vpc-id --custom-target-host your-target-host --custom-target-port your-target-port --local-port your-local-port\n```\n\nMinimal policy:\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"ec2:DescribeInstances\",\n      \"Resource\": \"*\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"ec2:StartInstances\",\n      \"Resource\": \"arn:aws:ec2:\u003cyour-region\u003e:\u003cyour-account-id\u003e:instance/\u003cyour-basti-instance-id\u003e\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"ec2:CreateTags\",\n      \"Resource\": \"arn:aws:ec2:\u003cyour-region\u003e:\u003cyour-account-id\u003e:instance/\u003cyour-basti-instance-id\u003e\"\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": \"ssm:StartSession\",\n      \"Resource\": [\n        \"arn:aws:ssm:*:*:document/AWS-StartPortForwardingSessionToRemoteHost\",\n        \"arn:aws:ec2:\u003cyour-region\u003e:\u003cyour-account-id\u003e:instance/\u003cyour-basti-instance-id\u003e\"\n      ],\n      \"Condition\": {\n        \"BoolIfExists\": {\n          \"ssm:SessionDocumentAccessCheck\": \"true\"\n        }\n      }\n    }\n  ]\n}\n```\n\n\u003c/details\u003e\n\n### Usage audit\n\nSince Basti uses IAM for access control, the connection history, along with the _responsible IAM user_ and all the connection details, can be audited using AWS CloudTrail by filtering on the \"StartSession\" event. Please, refer to the [AWS CloudTrail documentation](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html) for more details.\n\nA 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.\n\n### Shared configuration\n\nThe [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.\n\n## 🔐 Security\n\nSecurity is a top priority for Basti. The following sections describe the security measures taken by Basti.\n\n### Network\n\nThe bastion EC2 instance reachability from the Internet is completely disabled with AWS Security Groups configuration. _No ports are open for inbound traffic._ The bastion instance is only accessible through [AWS Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html).\n\nBasti automatically adjusts the target's Security Group to allow inbound traffic from the bastion instance's Security Group.\n\n### Access control\n\n[AWS Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html), which is used by Basti to establish a port forwarding session, doesn't use SSH keys for access control. Instead, it relies on [AWS IAM](https://aws.amazon.com/iam/) users and their permissions in your AWS account. This also means that [AWS CloudTrail](https://aws.amazon.com/cloudtrail/) could be used to _audit Basti usage_.\n\n### Software\n\nBasti uses the latest Amazon Linux 2 - Kernel 5.10 AMI available at the initialization time (`basti init` command) for the bastion instance.\n\nThe bastion instance EBS volume is encrypted by default.\n\nThe bastion instance is being stopped when it's not used for some short period of time. These shutdowns are also used to _update the bastion instance's software packages and OS kernel_. By default, the updates happen once a day but not more often than the bastion instance is used.\n\n## ❤️ Development\n\nFirst of all, thank you for your interest in contributing to Basti! 🎉\n\nThe following section describes how to run your local version of Basti CLI\nas you make changes to the code. Please, feel free to open an issue if you want to see Basti CDK development guide!\n\n### Build\n\nBefore proceeding to development, it's recommended to run the _full build_.\nThis requires Docker to be installed on your machine and may take a couple of minutes.\n\n```sh\nnpm run build\n```\n\nFull Basti build consists of two parts:\n\n1. Compiling Basti TypeScript code. The code has to be compiled after each change.\n\n   ```sh\n   npm run build-src\n\n   # Or, if you want to automatically recompile on each change:\n   npm run build-src-watch\n   ```\n\n2. Building non-NodeJS dependencies (AWS session-manger-plugin).\n   This step is only required after the first checkout or in a rare\n   case when the dependencies are updated.\n   ```sh\n   npm run build-deps\n   ```\n\n### Run\n\nAfter the build is complete, you can run Basti:\n\n```sh\nnpm run start -- \u003ccommand\u003e \u003coptions\u003e\n```\n\nAlternatively, you can link-install the local version of Basti in your system\nand use it as you would usually use Basti:\n\n```sh\n# Link-install the local version of Basti\nnpm link\n\n# Run Basti\nbasti \u003ccommand\u003e \u003coptions\u003e\n```\n\n### Test\n\nBefore submitting a pull request, please make sure that all the tests and\nchecks pass:\n\n```sh\nnpm run test\n```\n\n## License\n\nUsage is provided under the MIT License. See [LICENSE](https://github.com/basti-app/basti/blob/main/LICENSE) for the full details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasti-app%2Fbasti","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbasti-app%2Fbasti","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasti-app%2Fbasti/lists"}