Обновлять
Это Google I/O 21! и появятся новые функции: D
Один из них — это Cloud Run и Secret Manager, поэтому приходит обновление:
- Да, env_vars немного опасны, потому что в каком -то месте они были бы в простом тексте (например, консоль Cloud Run или файл, если вы используете объемы).
Но теперь мы можем установить нашу Envs непосредственно из секретного менеджера, это означает, что мы не сможем увидеть секреты на консоли (или в файле).
# Just add those secrets as envs when you deploy your service. # For this example I'm using 'latest', it's recommended to use a specific version. gcloud beta run deploy pets-api \ --image gcr.io/Project-A/pets-api:v0.1 \ --update-secrets=db_password=db_password_secret:latest
Еще один совет, который я хочу показать вам от Wietse Venema Из его книги Создание облачных приложений с помощью Google Cloud Run Анкет
» Чтобы добавить еще один барьер для предотвращения прямых соединений [к нашему экземпляру SQL Cloud], вы можете запросить SSL/TLS для этих [соединений]: «
gcloud sql instance patch --require-ssl my-pets-instance
Вот иди, ребята! Не забудьте следовать Лучшие практики из документации.
Безопасное соединение — это в основном сетевая тема, потому что она занимает инфраструктурные задачи. У GCP есть ресурсы и инструменты, которые мы можем использовать для решения этих задач в качестве разработчиков.
В этом случае у нас есть API, который возвращает список домашних животных из базы данных MySQL.
Наша цель — подключить наш API с Проект А в базу данных MySQL на Проект B Использование готовых к использованию инструментов от GCP.
Конечно, есть и другие способы подключения к экземпляру БД, таким как VPN, VPC для Privates IPS (для ресурсов без серверов вы можете использовать Без сервер VPC Connector например Облачные функции), брандмауэр и т. Д. Однако, как разработчики, мы можем воспользоваться ресурсами GCP, не должны беспокоиться об инфраструктуре, просто код!
Кстати, это соединение можно использовать только в одном проекте GCP
Архитектура
В этой архитектуре у нас есть два проекта GCP (A и B)
Как вы можете видеть на изображении:
- Наш API работает в облаке, запускающемся в Проект A .
- Наш экземпляр Cloud SQL (MySQL) работает на Проект B Анкет
Оба управляются GCP, поэтому мы крутые. Вот инструменты безопасности:
Cloud SQL Proxy
Cloud SQL Proxy позволяет авторизовать и защищать ваши подключения, используя разрешения управления идентификацией и доступом (IAM). Прокси проверяет соединения, используя учетные данные для учетной записи пользователя или службы, и обертывание соединения на уровне SSL/TLS, который разрешен для экземпляра SQL. Док
Секретный менеджер
Secret Manager — это безопасная и удобная система хранения для ключей API, паролей, сертификатов и других конфиденциальных данных. Secret Manager предоставляет центральное место и единственный источник истины для управления, доступа и секретов аудита в Google Cloud. Док
Достаточно теории, давайте немного кодируем: D
База данных (по проекту B)
На самом деле, создать экземпляр Cloud SQL с MySQL на GCP очень прост, просто следуйте этому Быстрый старт
Схема
Простая таблица для домашних животных
CREATE DATABASE petsbook; USE petsbook; CREATE TABLE pets ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) NOT NULL ); INSERT INTO pets (name) values ("Mel"); SELECT id, name from pets; -- 1, Mel (My pet)
Pets API (на проекте A)
main.py
from flask import Flask, jsonify import sqlalchemy app = Flask(__name__) def init_connection_engine(): db_user = "my-super-user" db_pass = "my-super-password" db_name = "my-pets-database" db_socket_dir = '/cloudsql' #: : " cloud_sql_connection_name = "Project-B:southamerica-east1:my-pets-instance" db_config = { "pool_size": 5, "max_overflow": 2, "pool_timeout": 30, # 30 seconds "pool_recycle": 1800, # 30 minutes } pool = sqlalchemy.create_engine( sqlalchemy.engine.url.URL( drivername="mysql+pymysql", username=db_user, password=db_pass, database=db_name, query={ "unix_socket": "{}/{}".format( db_socket_dir, cloud_sql_connection_name) } ), **db_config ) return pool @app.before_first_request def create_connection(): global db db = init_connection_engine() @app.route("/", methods=['GET']) def get_pets(): """ This method returns a list of pets from DB on Cloud SQL """ pets = [] with db.connect() as conn: pets_result = conn.execute("SELECT id, name from pets;").fetchall() for row in pets_result: pets.append({"id": row[0], "name": row[1]}) # Response return jsonify(pets), 200
Реализовать прокси -сервер SQL SQL
[По проекту A] Создайте учетную запись службы.
# Create Service Account (on Project A) gcloud iam service-accounts create pets-api-cred \ --description "Service Account for Pets API Service" \ --display-name "Pets API Service Account"
[По проекту B] Грант Cloud SQL> Клиентская роль к созданной вами учетной записи.
# Grant Cloud SQL Client role (on Project B) gcloud projects add-iam-policy-binding Project-B \ --member=serviceAccount:pets-api-cred@Project-A.iam.gserviceaccount.com \ --role="roles/cloudsql.client"
[ В проекте A] Создайте и разверните API на облачном забеге
# Build image docker build -t gcr.io/Project-A/pets-api:v0.1 . # Push to Container Register docker push gcr.io/Project-A/pets-api:v0.1 # Deploy to Cloud Run gcloud run deploy pets-api \ --image gcr.io/Project-A/pets-api:v0.1 \ --region southamerica-east1 \ --platform managed \ --allow-unauthenticated \ --add-cloudsql-instances Project-B:southamerica-east1:my-pets-instance \ --update-env-vars INSTANCE_CONNECTION_NAME="Project-B:southamerica-east1:my-pets-instance" \ --service-account pets-api-cred@Project-A.iam.gserviceaccount.com
-Адд-Клоудскл-Инстанции и -Update-env-vars Указывает на Cloud Run, где находится экземпляр Cloud SQL.
-Сервис-Участник Указывает Cloud Run для использования этой учетной записи службы.
Это мощное преимущество! Потому что нам не нужно загружать какой -либо ключ для учетной записи службы (например, файл json) Анкет
Попробуем наши Pets API
curl https://pets-api-[your-hash]-rj.a.run.app # [{"id":1,"name":"Mel"}]
Это работает! Но … подожди минутку … Пользователь и пароль обнажаются в коде .-.
Да, мы можем использовать переменные среды, чтобы скрыть информацию, но в некотором роде пользователь и пароль будут в простом тексту в каком -то месте.
Идея состоит в том, что вся конфиденциальная информация должна быть скрыта для всех, везде, даже на CI/CD.
Реализовать секретный менеджер
Все наши конфиденциальные информацию (например, пользователь и пароль) должны быть защищены, секретный менеджер является отличным ресурсом для этого.
Во -первых, создайте наш Секреты
# Enable Secret Manager gcloud services enable secretmanager.googleapis.com # Create a secret for each sensitive information gcloud secrets create db_user_secret --replication-policy="automatic" gcloud secrets create db_password_secret --replication-policy="automatic" gcloud secrets create db_name_secret --replication-policy="automatic" gcloud secrets create cloud_sql_connection_name_secret --replication-policy="automatic" # Create a version (contains the actual contents of a secret) for each secret gcloud secrets versions add db_user_secret --data-file="db_user_secret.txt" gcloud secrets versions add db_password_secret --data-file="db_password_secret.txt" gcloud secrets versions add db_name_secret --data-file="db_name_secret.txt" gcloud secrets versions add cloud_sql_connection_name_secret --data-file="cloud_sql_connection_name_secret.txt" # Add a secret version from the contents of a file on disk. # You can also add a secret version directly on the command line, # but this is discouraged because the plaintext will appear in your shell history. # Grant the Manager Secret Accessor role to our Service Account gcloud projects add-iam-policy-binding Project-A \ --member=serviceAccount:pets-api-cred@Project-A.iam.gserviceaccount.com \ --role="roles/secretmanager.secretAccessor"
Тогда мы должны получить доступ к информации по коду. Док
... def init_connection_engine(): # Create the Secret Manager client. client = secretmanager.SecretManagerServiceClient() # Build the resource name of the secret version. db_user_secret = f"projects/{PROJECT_ID}/secrets/db_user_secret/versions/latest" db_password_secret = f"projects/{PROJECT_ID}/secrets/db_password_secret/versions/latest" db_name_secret = f"projects/{PROJECT_ID}/secrets/db_name_secret/versions/latest" cloud_sql_conn_name_secret = f"projects/{PROJECT_ID}/secrets/cloud_sql_connection_name_secret/versions/latest" # Access the secret version. db_user_response = client.access_secret_version(request={"name": db_user_secret}) db_password_response = client.access_secret_version(request={"name": db_password_secret}) db_name_response = client.access_secret_version(request={"name": db_name_secret}) cloud_sql_conn_name_response = client.access_secret_version(request={"name": cloud_sql_conn_name_secret}) db_user = db_user_response.payload.data.decode("UTF-8") db_pass = db_password_response.payload.data.decode("UTF-8") db_name = db_name_response.payload.data.decode("UTF-8") db_socket_dir = '/cloudsql' cloud_sql_connection_name = cloud_sql_conn_name_response.payload.data.decode("UTF-8") db_config = { "pool_size": 5, "max_overflow": 2, "pool_timeout": 30, # 30 seconds "pool_recycle": 1800, # 30 minutes } pool = sqlalchemy.create_engine( sqlalchemy.engine.url.URL( drivername="mysql+pymysql", username=db_user, password=db_pass, database=db_name, query={ "unix_socket": "{}/{}".format( db_socket_dir, cloud_sql_connection_name) } ), **db_config ) return pool @app.before_first_request def create_connection(): global db db = init_connection_engine() ...
Большой! Все установлено, наши подключения безопасны, и наша конфиденциальная информация защищена:)
Весь код на GitHub https://github.com/alvardev/cloud-sql-connection
Надеюсь, это поможет вам!
Оригинал: «https://dev.to/alvardev/gcp-cloud-sql-secure-connection-between-projects-d2i»