如何创建工作堡垒主机以使用 AWS CDK v2 安全地访问 RDS 数据库?

问题描述 投票:0回答:1

我被告知这是最安全的方法,但我无法根据我在那里找到的分散且大多过时的信息拼凑出一个可行的解决方案。

使用 AWS CDK v2 部署堡垒、RDS 实例,这样我就可以通过终端或 DBeaver 使用 ssh 进行连接。

我尝试遵循这篇文章,这就是我解决的地方:

export class SshBastionRdsStack extends Stack {
    constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);

        const vpc = new Vpc(this, "SshBastionRdsVpc");

        const secret = new Secret(this, "SshBastionRdsUserSecret", {
            secretName: "pg-test-master-user-secret",
            description: "Database master user credentials",
            generateSecretString: {
                secretStringTemplate: JSON.stringify({ username: "postgres" }),
                generateStringKey: "password",
                passwordLength: 16,
                excludePunctuation: true
            },
        });

        const username = secret.secretValueFromJson("username").unsafeUnwrap().toString();
        const password = secret.secretValueFromJson("password");

        const rdsInstance = new DatabaseInstance(this, "SshBastionRdsDb", {
            vpc,
            credentials: { username, password },
            engine: DatabaseInstanceEngine.postgres({ version: PostgresEngineVersion.VER_15_4 }),
            instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.MICRO),
            backupRetention: Duration.days(0),
            deleteAutomatedBackups: true,
            removalPolicy: RemovalPolicy.DESTROY,
        });

        const bastionHost = new BastionHostLinux(this, "SshBastionRdsBastionHost", {
            instanceType: InstanceType.of(InstanceClass.T3, InstanceSize.NANO),
            machineImage: MachineImage.latestAmazonLinux2(),
            subnetSelection: { subnetType: SubnetType.PUBLIC },
            vpc
        });

        bastionHost.allowSshAccessFrom(Peer.anyIpv4());
        rdsInstance.connections.allowFrom(
            bastionHost.connections, 
            Port.tcp(rdsInstance.instanceEndpoint.port), 
            "Bastion host connection"
        );

        new CfnOutput(this, "SshBastionRdsBastionHostOutput", {
            value: bastionHost.instanceId
        });
    }
}

然后我生成了一个密钥对:

ssh-keygen -t rsa -m pem

更改私钥的权限:

sudo chmod 400 ~/.ssh/cdk-ssh-bastion-rds

向堡垒主机添加公钥:

aws ec2-instance-connect send-ssh-public-key \
    --instance-id i-xxxxxxxxxxxxxxx \
    --instance-os-user ec2-user \
    --ssh-public-key file:///Users/me/.ssh/cdk-ssh-bastion-rds.pub

我可以成功连接到堡垒ec2实例:

ssh -i ~/.ssh/cdk-ssh-bastion-rds -l ec2-user XXX.XX.XXX.XX

...这给了我:

Last login: Sun Mar  3 02:17:11 2024 from xxxx.xxxx.xxxx.xxxx
   ,     #_
   ~\_  ####_        Amazon Linux 2
  ~~  \_#####\
  ~~     \###|       AL2 End of Life is 2025-06-30.
  ~~       \#/ ___
   ~~       V~' '->
    ~~~         /    A newer version of Amazon Linux is available!
      ~~._.   _/
         _/ _/       Amazon Linux 2023, GA and supported until 2028-03-15.
       _/m/'           https://aws.amazon.com/linux/amazon-linux-2023/

[ec2-user@ip-10-0-2-69 ~]$

奇怪的是,我不能这样做两次。如果我

exit
并重试,我会得到以下信息:

[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

如果我再次

aws ec2-instance-connect send-ssh-public-key
并重试...它会再次连接。这是怎么回事?它不是在会话之间存储公钥吗?

无论如何...继续前进。

如果我尝试通过堡垒攻击 RDS:

ssh -i ~/.ssh/cdk-ssh-bastion-rds -f -N -L 22:sshbastionrdsstack-sshbastionrdsxxxxxxxxx-xxxxxxxxxxxxxx.xxxxxxxxxxxxx.us-east-1.rds.amazonaws.com:5432 [email protected] -v
OpenSSH_9.0p1, LibreSSL 3.3.6
debug1: Reading configuration data /Users/me/.ssh/config
debug1: /Users/me/.ssh/config line 2: Applying options for *
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 21: include /etc/ssh/ssh_config.d/* matched no files
debug1: /etc/ssh/ssh_config line 54: Applying options for *
debug1: Authenticator provider $SSH_SK_PROVIDER did not resolve; disabling
debug1: Connecting to XXX.XX.XXX.XX [XXX.XX.XXX.XX] port 22.
debug1: Connection established.
debug1: identity file /Users/me/.ssh/cdk-ssh-bastion-rds type 0
debug1: identity file /Users/me/.ssh/cdk-ssh-bastion-rds-cert type -1
debug1: identity file /Users/me/.ssh/id_rsa_personal type 0
debug1: identity file /Users/me/.ssh/id_rsa_personal-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_9.0
debug1: Remote protocol version 2.0, remote software version OpenSSH_7.4
debug1: compat_banner: match: OpenSSH_7.4 pat OpenSSH_7.4* compat 0x04000006
debug1: Authenticating to XXX.XX.XXX.XX:22 as 'ec2-user'
debug1: load_hostkeys: fopen /Users/me/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ssh-ed25519
debug1: kex: server->client cipher: [email protected] MAC: <implicit> compression: none
debug1: kex: client->server cipher: [email protected] MAC: <implicit> compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: SSH2_MSG_KEX_ECDH_REPLY received
debug1: Server host key: ssh-ed25519 SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
debug1: load_hostkeys: fopen /Users/me/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: Host 'XXX.XX.XXX.XX' is known and matches the ED25519 host key.
debug1: Found key in /Users/me/.ssh/known_hosts:26
debug1: rekey out after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey in after 134217728 blocks
debug1: get_agent_identities: bound agent to hostkey
debug1: get_agent_identities: agent returned 3 keys
debug1: Will attempt key: /Users/me/.ssh/id_rsa_personal RSA SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx explicit agent
debug1: Will attempt key: /Users/me/.ssh/cdk-ssh-bastion-rds RSA SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx explicit agent
debug1: Will attempt key: /Users/me/.ssh/cdk-ssh-bastion-rds RSA SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx agent
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<rsa-sha2-256,rsa-sha2-512>
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic
debug1: Next authentication method: publickey
debug1: Offering public key: /Users/me/.ssh/id_rsa_personal RSA SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx explicit agent
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic
debug1: Offering public key: /Users/me/.ssh/cdk-ssh-bastion-rds RSA SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx explicit agent
debug1: Server accepts key: /Users/me/.ssh/cdk-ssh-bastion-rds RSA SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx explicit agent
Authenticated to XXX.XX.XXX.XX ([XXX.XX.XXX.XX]:22) using "publickey".
debug1: Local connections to LOCALHOST:22 forwarded to remote address sshbastionrdsstack-sshbastionrdsxxxxxxxxx-xxxxxxxxxxxxxx.xxxxxxxxxxxxx.us-east-1.rds.amazonaws.com:5432
debug1: Local forwarding listening on ::1 port 22.
bind [::1]:22: Permission denied
debug1: Local forwarding listening on 127.0.0.1 port 22.
bind [127.0.0.1]:22: Permission denied
channel_setup_fwd_listener_tcpip: cannot listen to port: 22
Could not request local forwarding.
debug1: Requesting [email protected]
debug1: forking to background
debug1: Entering interactive session.
debug1: pledge: filesystem
(base) me@VGJ-MBP-M2X cdk-ssh-bastion-rds % debug1: client_input_global_request: rtype [email protected] want_reply 0
debug1: client_input_hostkeys: searching /Users/me/.ssh/known_hosts for XXX.XX.XXX.XX / (none)
debug1: client_input_hostkeys: searching /Users/me/.ssh/known_hosts2 for XXX.XX.XXX.XX / (none)
debug1: client_input_hostkeys: hostkeys file /Users/me/.ssh/known_hosts2 does not exist
debug1: client_global_hostkeys_private_confirm: server used untrusted RSA signature algorithm ssh-rsa for key 0, disregarding
debug1: update_known_hosts: known hosts file /Users/me/.ssh/known_hosts2 does not exist

最终它超时并让我回到提示符,没有任何其他反馈。

第二次运行最后也给了我这个:

[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
amazon-web-services amazon-ec2 ssh amazon-rds aws-cdk
1个回答
0
投票

我猜你本地的端口 22 要么已经绑定到 SSH,要么你无法绑定该端口,因为它低于 1024,因此它是一个特权端口(因此只有在运行 SSH 时它才可以工作(如果不在本地使用) sudo/管理员权限 - 但这不是好的做法,也没有必要)。

我建议您使用高于 1024 的端口更改

-L 22:sshbastionrdsstack-sshbastionrdsxxxxxxxxx-xxxxxxxxxxxxxx.xxxxxxxxxxxxx.us-east-1.rds.amazonaws.com:5432
参数中的端口 22(如果您没有运行本地数据库实例,5432 可能是一个不错的选择,但实际上什么端口并不重要,只要它高于 1024 并且未使用)。连接 SSH 后,您将能够连接到 localhost:5432(或者您用于传递给
-L
争论的第一个数字的任何端口)。连接将从 localhost:[您的端口] -> 通过 SSH 端口 22 转发到实例 -> 然后使用
-L
参数的第三个参数中指定的端口从堡垒转发到目的地。

您可能还需要添加一个安全组,以允许堡垒主机与 5432 上的 RDS 进行通信。建议的方法是使用“自引用安全组”——即仅允许 5432 自身的安全组。然后将该安全组添加到 RDS 和堡垒实例。我还没有测试过它,但 Github 上有一个 CDK gist

至于您的SSH密钥问题,这是预期的:

将 SSH 公钥推送到指定的 EC2 实例以供使用 指定用户。密钥保留 60 秒。了解更多信息, 请参阅使用 EC2 Instance Connect 连接到您的 Linux 实例 亚马逊 EC2 用户指南 .

我想到了 2 个选项:

  1. 在本地编写一个脚本,依次调用这两个命令(这可能更安全,就像您在本地旋转密钥一样,不需要更新堡垒)
  2. 一次性登录实例并运行
    echo "[Paste your Pub Key here]" >> ~/.ssh/authorizied_keys && chmod 400 ~/.ssh/authorizied_keys
    以保留您的密钥。
© www.soinside.com 2019 - 2024. All rights reserved.