安全高效地存储 Cloud SQL 凭证以在 Cloud Function 中使用

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

我正在尝试使用 Secrets Manager 从我的 Cloud Function 安全连接到 Cloud SQL (postgres) 实例。然而,我很困惑

  • 什么应该被存储为秘密,
  • 多个秘密是否应单独存储,以及
  • 如何从云功能访问这些秘密

鉴于此示例代码,

    # Note: Saving credentials in environment variables is convenient, but not
    # secure - consider a more secure solution such as
    # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
    # keep secrets safe.

    instance_connection_name = os.environ[
        "INSTANCE_CONNECTION_NAME"
    ]  # e.g. 'project:region:instance'
    db_user = os.environ["DB_USER"]  # e.g. 'my-db-user'
    db_pass = os.environ["DB_PASS"]  # e.g. 'my-db-password'
    db_name = os.environ["DB_NAME"]  # e.g. 'my-database'

    ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

    # initialize Cloud SQL Python Connector object
    connector = Connector()

    def getconn() -> pg8000.dbapi.Connection:
        conn: pg8000.dbapi.Connection = connector.connect(
            instance_connection_name,
            "pg8000",
            user=db_user,
            password=db_pass,
            db=db_name,
            ip_type=ip_type,
        )
        return conn

我确定了四个设置:实例连接名称、数据库用户、数据库密码和数据库名称(代码来自 https://cloud.google.com/sql/docs/postgres/connect-functions)。

另外,当我看到这篇文章时, 这意味着实例连接名称、数据库用户和数据库密码应作为秘密存储。

我的第一个问题是,这 3 个都应该作为单独的机密存储在 Secrets Manager 中吗?或者它们应该以某种格式存在于一个秘密中? 例如JSON 格式

{ "db_user": "my-db-user", "db_pass": "my-db-password", "instance_connection_name": "xxx" }

当机密作为卷安装时,从性能角度来看,后者更容易检索,但安全性较低,因为攻击者需要破坏对单个机密的访问才能连接到数据库,而不是三个。

第二个问题与上述评论相关:考虑到连接到 SQL 数据库的开销,我是否应该尝试通过将我的秘密公开为环境变量而不是将它们安装为卷来提高性能?

第三个问题是数据库名怎么办。第二篇文章中没有指定,但是将数据库名称存储在环境变量中是否安全,或者也应该存储为秘密?

作为参考,这是我当前的代码,它将数据库用户/密码和实例连接名称存储在秘密中,并将它们作为卷安装在云功能中:

import sqlalchemy
from google.cloud.sql.connector import Connector, IPTypes

connector = Connector()

def getconn():
    with open(
        "/etc/secrets1/instance-connection-name", "r", encoding="utf-8"
    ) as f:
        instance_connection_name = f.read()
    with open("/etc/secrets2/db-user", "r", encoding="utf-8") as f:
        db_user = f.read()
    with open("/etc/secrets3/db-pass", "r", encoding="utf-8") as f:
        db_pass = f.read()

    db_name = os.environ.get("DB_NAME")

    conn = connector.connect(
       instance_connection_name,
        "pg8000",
        user=db_user,
        password=db_pass,
        db=db_name,
        ip_type=IPTypes.PUBLIC,
    )
    return conn


pool = sqlalchemy.create_engine(
    "postgresql+pg8000://",
    creator=getconn,
)


def main():
    with pool.connect() as db_conn:
        results = db_conn.execute(
            sqlalchemy.text(
                "select * from pets"
            )
        ).fetchall()

    return results
google-cloud-platform google-cloud-functions google-cloud-sql
1个回答
0
投票

对于您的问题:

  1. 更喜欢独立存储秘密。有些可以比其他进化得更快,如果你有统一的秘密,就更容易维护。
  2. Env var 表示读取内存中的值。读取卷中的秘密意味着读取内存中的值(没有附加磁盘,它是内存中的虚拟卷)。它大致相当(文件选项应该重一点,但它被数据库连接持续时间最小化/隐藏)
  3. 取决于你。我通常不会保守秘密。

如果最佳解决方案不是使用登录名/密码而只是使用 Cloud Functions 身份登录 PostgreSQL 实例怎么办?

看看这里,这是我推荐的方式:https://cloud.google.com/sql/docs/postgres/authentication

© www.soinside.com 2019 - 2024. All rights reserved.