Skip to content

Conversation

@zhangzqs
Copy link
Collaborator

@zhangzqs zhangzqs commented Nov 4, 2025

No description provided.

包括 data.tf、main.tf、mysql_master.sh、mysql_slave.sh、outputs.tf、variables.tf、versions.tf 等文件
@gemini-code-assist
Copy link

Summary of Changes

Hello @zhangzqs, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求引入了用于在 Qiniu 云平台上部署 MySQL 数据库的 Terraform 配置。它提供了两种部署模式:一种是高可用的主从复制集群,另一种是独立的单节点实例。这些配置旨在简化 MySQL 基础设施的自动化部署和管理,通过可配置的变量和自动化脚本,用户可以快速地创建和配置满足其特定需求的 MySQL 环境。

Highlights

  • MySQL 主从复制集群: 新增 Terraform 配置,用于在 Qiniu 云上部署一个 MySQL 主从复制集群,包括一个主节点和多个从节点。
  • MySQL 单节点实例: 新增 Terraform 配置,用于在 Qiniu 云上部署一个独立的 MySQL 单节点实例。
  • 自动化配置脚本: 提供了 'mysql_master.sh', 'mysql_slave.sh', 和 'mysql_standalone.sh' 脚本,用于自动化 MySQL 服务器的安装、基本配置、用户创建以及主从复制设置。
  • 参数化和验证: 所有配置都通过 Terraform 变量进行参数化,并包含严格的输入验证,确保部署的灵活性和安全性,特别是对 MySQL 用户名和密码的验证。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 增加了用于创建 MySQL 单节点实例和主从复制集群的 Terraform 模块,代码结构清晰。审查中发现了一些需要解决的问题,包括安全漏洞(例如,为复制用户使用管理员密码、在 shell 脚本中暴露密码、开放的绑定地址)、正确性错误(脚本语法错误、变量名不正确、脆弱的等待逻辑)以及可维护性方面的改进(使配置更健壮和灵活)。请查看具体的审查意见。

echo "MySQL not found, installing..."
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client-8.0 mysql-server-8.0 mysql-router mysql-shell
fi``

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

这里有一个语法错误。fi``` 应该是 fi`。多余的反引号会导致脚本执行失败。

Suggested change
fi``
fi

echo "Setting up MySQL standalone instance..."

# 允许外部IP访问
sed -i 's/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

对于单机版 MySQL,将 bind-address 设置为 0.0.0.0 会使数据库服务暴露在所有网络接口上。如果实例有公网 IP,这将是一个严重的安全风险,允许任何人尝试连接数据库。建议默认绑定到 127.0.0.1,仅在需要远程访问时通过变量进行配置。

mysql_admin_username = var.mysql_username
mysql_admin_password = var.mysql_password
mysql_replication_username = local.replication_username
mysql_replication_password = var.mysql_password

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

将管理员密码 var.mysql_password 同时用作复制用户的密码存在严重安全风险。如果复制用户的密码泄露,攻击者可能会尝试用它来登录管理账户。建议为复制用户创建一个独立的密码。您可以通过一个新的变量(例如 var.mysql_replication_password)来传递,或者使用 random_password 资源生成一个随机密码。

    mysql_replication_password = var.mysql_replication_password

default = ""

validation {
condition = var.mysql_db_name == null ? true : (

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

验证条件 var.mysql_db_name == null 是不正确的。因为该变量的 default""(空字符串),而不是 null。当用户不提供这个值时,var.mysql_db_name 的值是 ""== null 的判断会失败,导致验证逻辑出错。应该使用 var.mysql_db_name == ""

    condition = var.mysql_db_name == "" ? true : (

mysql_master_ip = qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4
mysql_server_id = tostring(count.index + 2) // 从库ID从2开始递增
mysql_replication_username = local.replication_username
mysql_replication_password = var.mysql_password

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

将管理员密码 var.mysql_password 同时用作复制用户的密码存在严重安全风险。如果复制用户的密码泄露,攻击者可能会尝试用它来登录管理账户。建议为复制用户创建一个独立的密码。您可以通过一个新的变量(例如 var.mysql_replication_password)来传递,或者使用 random_password 资源生成一个随机密码。

    mysql_replication_password = var.mysql_replication_password


# 重启 MySQL 服务
systemctl restart mysql
sleep 1 # 等待 MySQL 服务重启完成

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

使用 sleep 1 来等待 MySQL 重启完成是不可靠的。在负载较高或启动较慢的机器上,1秒可能不足以让 MySQL 完全准备好,导致后续命令失败。建议使用一个循环来检查 MySQL 服务的状态,例如通过 mysqladmin ping,直到服务可用为止。

Suggested change
sleep 1 # 等待 MySQL 服务重启完成
while ! mysqladmin ping --silent; do sleep 1; done

Comment on lines +7 to +10
ubuntu_image_id = [
for item in data.qiniu_compute_images.available_official_images.items : item
if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS"
][0].id

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

当前查找 Ubuntu 镜像 ID 的方式比较脆弱。如果 data.qiniu_compute_images.available_official_images.items 没有返回任何匹配 "Ubuntu" 和 "24.04 LTS" 的镜像,[0].id 的访问会直接导致 Terraform 执行失败。建议使用 one() 函数来确保只找到一个匹配的镜像,如果找不到或找到多个,它会返回一个更明确的错误信息。

  ubuntu_image_id = one([for item in data.qiniu_compute_images.available_official_images.items : item if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS"]).id


# 重启 MySQL 服务
systemctl restart mysql
sleep 1 # 等待 MySQL 服务重启完成

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

使用 sleep 1 来等待 MySQL 重启完成是不可靠的。在负载较高或启动较慢的机器上,1秒可能不足以让 MySQL 完全准备好,导致后续命令失败。建议使用一个循环来检查 MySQL 服务的状态,例如通过 mysqladmin ping,直到服务可用为止。

Suggested change
sleep 1 # 等待 MySQL 服务重启完成
while ! mysqladmin ping --silent; do sleep 1; done

Comment on lines +10 to +18
variable "instance_system_disk_size" {
type = number
description = "System disk size in GiB"

validation {
condition = var.instance_system_disk_size > 0
error_message = "instance_system_disk_size parameter must be a positive integer"
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

变量 instance_system_disk_size 没有设置默认值,而 replication 模块中的同名变量设置了 default = 20。为了保持一致性并提高模块易用性,建议在此处也添加一个默认值。

variable "instance_system_disk_size" {
  type        = number
  description = "System disk size in GiB"
  default     = 20

  validation {
    condition     = var.instance_system_disk_size > 0
    error_message = "instance_system_disk_size parameter must be a positive integer"
  }
}


# 创建 MySQL 从库节点
resource "qiniu_compute_instance" "mysql_replication_nodes" {
depends_on = [qiniu_compute_instance.mysql_primary_node]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

这里的 depends_on 是多余的。因为在第57行 user_data 中已经通过 qiniu_compute_instance.mysql_primary_node.private_ip_addresses[0].ipv4 引用了主节点,Terraform 会自动推断出依赖关系。显式声明 depends_on 会使代码变得冗余,建议移除。

echo "MySQL not found, installing..."
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-client-8.0 mysql-server-8.0 mysql-router mysql-shell
fi``
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Syntax Error

There are extra backticks at the end of this line (`fi```) which will cause a bash syntax error and script failure.

Suggested change
fi``
fi

image_id = local.ubuntu_image_id
system_disk_size = var.instance_system_disk_size

user_data = base64encode(templatefile("${path.module}/mysql_master.sh", {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Security: Passwords Exposed in Terraform State

Passing passwords directly in user_data causes multiple security vulnerabilities:

  • Passwords stored in plaintext in Terraform state files
  • Exposed in cloud provider logs and instance metadata
  • Visible in process listings during execution

Recommendation: Use a secrets management solution (AWS Secrets Manager, HashiCorp Vault, etc.) and retrieve credentials at runtime, or generate random passwords within the instance and store them securely.

References: CWE-312, CWE-532

echo "This is the primary node."

# 允许外部IP访问
sed -i 's/^bind-address\s*=\s*127.0.0.1/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Security: MySQL Exposed Without Firewall Rules

Binding to 0.0.0.0 exposes MySQL on all network interfaces, but the Terraform configuration doesn't include any security groups or firewall rules to restrict access.

Impact: MySQL instances accessible from entire network, vulnerable to brute force attacks and exploitation.

Recommendation: Add security group/firewall resources in Terraform to restrict port 3306 access to specific IP ranges or VPC subnets only.

fi

# 查看数据库
mysql -u"${mysql_admin_username}" -p"${mysql_admin_password}" -e "SHOW DATABASES;"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Security: Credentials Exposed in Process Listing

Passing passwords via command-line arguments (-p"${password}") exposes them in:

  • Process listings (ps aux) visible to all users
  • Shell history files
  • System logs

Recommendation: Use MySQL config files instead:

cat > /root/.my.cnf <<MYCNF
[client]
user=${mysql_admin_username}
password=${mysql_admin_password}
MYCNF
chmod 600 /root/.my.cnf
mysql -e "SHOW DATABASES;"

Reference: CWE-214

default = ""

validation {
condition = var.mysql_db_name == null ? true : (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Bug: Validation Logic Error

This validation checks for null but the variable has default = "" (empty string). The condition will never work correctly.

The replication module correctly uses var.mysql_db_name == "" at line 64 of mysql/replication/variables.tf.

Suggested change
condition = var.mysql_db_name == null ? true : (
condition = var.mysql_db_name == "" ? true : (

ubuntu_image_id = [
for item in data.qiniu_compute_images.available_official_images.items : item
if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS"
][0].id
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: Unsafe Array Access

Directly accessing [0] without checking if the array is empty will cause Terraform to fail if no Ubuntu 24.04 LTS image is found.

Recommendation: Add error handling:

  ubuntu_images = [
    for item in data.qiniu_compute_images.available_official_images.items : item
    if item.os_distribution == "Ubuntu" && item.os_version == "24.04 LTS"
  ]
  ubuntu_image_id = length(local.ubuntu_images) > 0 ? local.ubuntu_images[0].id : (
    # Trigger a clear error message
    tobool("ERROR: Ubuntu 24.04 LTS image not found")
  )

sleep 1 # 等待 MySQL 服务重启完成

# 轮询等待主库启动
while ! mysqladmin ping -h "${mysql_master_ip}" -u"${mysql_replication_username}" -p"${mysql_replication_password}" --silent; do
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High Priority: Unbounded Polling Loop

This while loop has no timeout, which could cause infinite waiting if the master fails to start.

Recommendation: Add timeout and exponential backoff:

MAX_RETRIES=60
RETRY_COUNT=0
SLEEP_TIME=2

while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
  if mysqladmin ping -h "${mysql_master_ip}" -u"${mysql_replication_username}" -p"${mysql_replication_password}" --silent; then
    echo "MySQL master is ready!"
    break
  fi
  echo "Waiting for MySQL master... (attempt $((RETRY_COUNT + 1))/$MAX_RETRIES)"
  sleep $SLEEP_TIME
  RETRY_COUNT=$((RETRY_COUNT + 1))
  SLEEP_TIME=$((SLEEP_TIME > 10 ? 10 : SLEEP_TIME + 1))
done

if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then
  echo "ERROR: MySQL master failed to become ready"
  exit 1
fi


# 创建 MySQL 从库节点
resource "qiniu_compute_instance" "mysql_replication_nodes" {
depends_on = [qiniu_compute_instance.mysql_primary_node]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance: Unnecessary Serialization

The depends_on forces all replica nodes to wait for complete master provisioning (including user_data execution), which blocks parallelization.

Since mysql_slave.sh already has a polling loop to wait for the master, this dependency can be removed to allow parallel instance provisioning, significantly reducing deployment time.

Recommendation: Remove depends_on to enable ~30-60% faster deployments.

mysql -uroot <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED BY '${mysql_admin_password}';
CREATE USER '${mysql_admin_username}'@'%' IDENTIFIED BY '${mysql_admin_password}';
GRANT ALL PRIVILEGES ON *.* TO '${mysql_admin_username}'@'%' WITH GRANT OPTION;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security: Overly Permissive Privileges

Granting ALL PRIVILEGES ON *.* with GRANT OPTION from any host ('%') violates the principle of least privilege.

Recommendations:

  1. Restrict host to specific IP ranges: '10.0.0.0/255.0.0.0'
  2. Grant only necessary privileges instead of ALL
  3. Remove GRANT OPTION unless required
  4. Create separate users for different purposes

Reference: CWE-250

@@ -0,0 +1,3 @@
provider "qiniu" {}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Provider Version Constraints

No version constraints specified for providers, which can lead to unpredictable behavior across environments.

Recommendation:

Suggested change
provider "qiniu" {}
terraform {
required_providers {
qiniu = {
source = "qiniu/qiniu"
version = "~> 1.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
}
required_version = ">= 1.0"
}
provider "qiniu" {}


# 配置从库,将自动将主库所有变更都同步过来,包括用户配置
mysql -uroot <<EOF
CHANGE MASTER TO
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deprecated MySQL Syntax

MySQL 8.0.23+ deprecated MASTER/SLAVE terminology in favor of SOURCE/REPLICA.

Recommendation: Update to modern syntax:

CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = '${mysql_master_ip}',
  SOURCE_USER = '${mysql_replication_username}',
  SOURCE_PASSWORD = '${mysql_replication_password}',
  SOURCE_AUTO_POSITION = 1;
START REPLICA;
SHOW REPLICA STATUS\G;

@xgopilot
Copy link

xgopilot bot commented Nov 4, 2025

Code Review Summary

I've completed a comprehensive review using specialized agents for code quality, security, performance, and documentation. The modules are well-structured, but several critical issues must be addressed before merging.

Critical Issues (Must Fix)

  1. Security: Passwords exposed in Terraform state and process listings (see inline comments)
  2. Security: MySQL exposed without firewall rules - binding to 0.0.0.0 with no network restrictions
  3. Bug: Syntax error in mysql_standalone.sh line 12 (extra backticks)
  4. Bug: Validation logic error in standalone/variables.tf checks null instead of ""
  5. Bug: Unsafe array access in data.tf will fail if Ubuntu 24.04 LTS image not found

High Priority

  • Add timeout/retry logic to slave polling loop to prevent infinite waiting
  • Reduce overly permissive MySQL user privileges (ALL on . from '%')
  • Add provider version constraints to prevent unpredictable behavior

Performance Optimization

  • Remove depends_on in replication module to enable parallel provisioning (~30-60% faster deployments)

Additional Recommendations

  • Update deprecated MySQL MASTER/SLAVE syntax to SOURCE/REPLICA
  • Add module README files with usage examples
  • Consider using secrets management instead of passing passwords in user_data

Overall, the Terraform structure is solid, but the security posture needs significant improvement before production use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant