侧边栏壁纸
博主头像
JavaLYG 博主等级

行动起来,活在当下

  • 累计撰写 95 篇文章
  • 累计创建 75 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

在openwer上用shell脚本自动更新阿里云RDS数据库实例ip白名单

liuyg
2025-03-10 / 0 评论 / 0 点赞 / 24 阅读 / 0 字

背景

家用ip经常会变动,数据库经常连不上,就得登录阿里云设置数据库白名单,做这个脚本部署到openwrt上定时运行就可以不用每次都手动更新了,也可以部署其他机器上

脚本内容

#!/bin/sh
# ---------------------------
# 阿里云RDS白名单更新脚本(纯净输出版)
# 版本:24.0
# ---------------------------

# 配置区
ACCESS_KEY_ID="xxx"
ACCESS_KEY_SECRET="xxx"
REGION_ID="cn-hangzhou"
INSTANCE_ID="rm-xxxxx"
SECURITY_GROUP_NAME="xxx"
IP_FILE="/tmp/last_ip.txt"
LOG_FILE="/tmp/rds_whitelist.log"

# ----------- 初始化 -----------
exec >>"$LOG_FILE" 2>&1
echo "==== 任务开始: $(date '+%Y-%m-%d %H:%M:%S') ===="

# 函数:RFC 3986编码
url_encode() {
  echo -n "$1" | awk '
    BEGIN {
      hextab = "0123456789ABCDEF"
      for (i = 0; i <= 255; i++) ord[sprintf("%c",i)] = i
    }
    {
      len = length($0)
      for (i = 1; i <= len; i++) {
        c = substr($0, i, 1)
        if (c ~ /[a-zA-Z0-9_.~-]/) {
          printf c
        } else {
          printf "%%%s", toupper(sprintf("%02x", ord[c]))
        }
      }
    }'
}

# 函数:获取公网IP(修复输出污染)
get_public_ip() {
  echo "[DEBUG] 开始获取公网IP..." >&2
  for src in "http://checkip.amazonaws.com" "http://ipecho.net/plain" "http://ifconfig.me"; do
    echo "[DEBUG] 尝试从 $src 获取IP" >&2
    ip=$(curl -s -4 --connect-timeout 5 "$src" | grep -oE "[0-9]{1,3}(\\.[0-9]{1,3}){3}")
    [ -n "$ip" ] && { 
      echo "[INFO] 成功获取IP: $ip" >&2
      echo "$ip"  # 关键修复:仅输出IP到stdout
      return
    }
  done
  echo "[ERROR] 所有IP源均不可用" >&2
  echo ""
}

# 主流程
echo "[INFO] 正在检查公网IP..."
CURRENT_IP=$(get_public_ip)
[ -z "$CURRENT_IP" ] && {
  echo "[ERROR] IP获取失败"
  exit 1
}

# IP变动检查
echo "[INFO] 检查IP变动..."
if [ -f "$IP_FILE" ]; then
  LAST_IP=$(cat "$IP_FILE")
  echo "[DEBUG] 上次记录的IP: $LAST_IP" >&2
  [ "$CURRENT_IP" = "$LAST_IP" ] && {
    echo "[INFO] IP未变化,无需更新" >&2
    exit 0
  }
else
  echo "[DEBUG] 未找到历史IP记录文件" >&2
fi

# ----------- 签名参数构造 -----------
echo "[INFO] 开始构造签名参数..." >&2
ALGORITHM="ACS3-HMAC-SHA256"
HTTP_METHOD="POST"
HOST="rds.aliyuncs.com"
CANONICAL_URI="/"
ACTION="ModifySecurityIps"
VERSION="2014-08-15"
UTC_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
NONCE=$(cat /proc/sys/kernel/random/uuid 2>/dev/null || date +%s%N | md5sum | cut -c1-32)

echo "[DEBUG] 生成随机数Nonce: $NONCE" >&2
echo "[DEBUG] UTC时间戳: $UTC_DATE" >&2

# 构造查询参数
PARAMS="Action=$ACTION
DBInstanceId=$INSTANCE_ID
SecurityIps=$CURRENT_IP
DBInstanceIPArrayName=$SECURITY_GROUP_NAME
WhitelistNetworkType=MIX
ModifyMode=Cover"

echo "[DEBUG] 原始参数列表:" >&2
echo "$PARAMS" >&2

# 参数排序编码
CANONICAL_QUERY=$(echo "$PARAMS" | while IFS='=' read -r key value; do
  encoded_key=$(url_encode "$key")
  encoded_value=$(url_encode "$value")
  echo "${encoded_key}=${encoded_value}"
done | sort -t= -k1 | tr '\n' '&' | sed 's/&$//')

echo "[DEBUG] 编码后的规范查询字符串:" >&2
echo "$CANONICAL_QUERY" >&2

# 构造规范请求
HASHED_PAYLOAD=$(echo -n "" | openssl sha256 | awk '{print $2}')
echo "[DEBUG] 空请求体哈希值: $HASHED_PAYLOAD" >&2

HEADERS="host:$HOST
x-acs-action:$ACTION
x-acs-version:$VERSION
x-acs-date:$UTC_DATE
x-acs-signature-nonce:$NONCE
x-acs-content-sha256:$HASHED_PAYLOAD"

# 处理规范头
CANONICAL_HEADERS=$(echo "$HEADERS" | while read line; do
  key=$(echo "$line" | cut -d':' -f1 | tr 'A-Z' 'a-z')
  value=$(echo "$line" | cut -d':' -f2- | sed 's/^ *//')
  echo "${key}:${value}"
done | sort | tr '\n' '\n')

SIGNED_HEADERS=$(echo "$HEADERS" | cut -d':' -f1 | tr 'A-Z' 'a-z' | sort | tr '\n' ';' | sed 's/;$//')

echo "[DEBUG] 规范头内容:" >&2
echo "$CANONICAL_HEADERS" >&2
echo "[DEBUG] 签名头列表: $SIGNED_HEADERS" >&2

CANONICAL_REQUEST="${HTTP_METHOD}\n${CANONICAL_URI}\n${CANONICAL_QUERY}\n${CANONICAL_HEADERS}\n\n${SIGNED_HEADERS}\n${HASHED_PAYLOAD}"
echo "[DEBUG] 规范请求内容:" >&2
echo -e "$CANONICAL_REQUEST" >&2

# 计算签名
HASHED_REQUEST=$(echo -en "$CANONICAL_REQUEST" | openssl sha256 | awk '{print $2}')
STRING_TO_SIGN="${ALGORITHM}\n${HASHED_REQUEST}"
echo "[DEBUG] 签名字符串:" >&2
echo -e "$STRING_TO_SIGN" >&2

SIGNATURE=$(echo -en "$STRING_TO_SIGN" | openssl dgst -sha256 -mac HMAC -macopt "key:${ACCESS_KEY_SECRET}" | awk '{print $2}')
echo "[DEBUG] 计算得到的签名: $SIGNATURE" >&2

# 构造Authorization头
AUTHORIZATION="${ALGORITHM} Credential=${ACCESS_KEY_ID},SignedHeaders=${SIGNED_HEADERS},Signature=${SIGNATURE}"
echo "[DEBUG] Authorization头: $AUTHORIZATION" >&2

# 发送请求
echo "[INFO] 正在发送API请求..." >&2
FULL_URL="https://${HOST}/?${CANONICAL_QUERY}"
echo "[DEBUG] 完整请求URL: ${FULL_URL%&Signature=*}" >&2

RESPONSE=$(curl -s -X POST \
  -H "host: $HOST" \
  -H "x-acs-action: $ACTION" \
  -H "x-acs-version: $VERSION" \
  -H "x-acs-date: $UTC_DATE" \
  -H "x-acs-signature-nonce: $NONCE" \
  -H "x-acs-content-sha256: $HASHED_PAYLOAD" \
  -H "Authorization: $AUTHORIZATION" \
  "$FULL_URL")

echo "[DEBUG] 原始响应内容:" >&2
echo "$RESPONSE" >&2

# 处理响应
if echo "$RESPONSE" | grep -q '"TaskId"'; then
  echo "[INFO] 白名单更新成功" >&2
  TASK_ID=$(echo "$RESPONSE" | grep -o '"TaskId":"[^"]*"' | cut -d'"' -f4)
  REQUEST_ID=$(echo "$RESPONSE" | grep -o '"RequestId":"[^"]*"' | cut -d'"' -f4)
  echo "$CURRENT_IP" > "$IP_FILE"
  echo "[SUCCESS] 任务ID: $TASK_ID, 请求ID: $REQUEST_ID" >&2
else
  ERROR_MSG=$(echo "$RESPONSE" | grep -o '"Message":"[^"]*"' | cut -d'"' -f4)
  REQUEST_ID=$(echo "$RESPONSE" | grep -o '"RequestId":"[^"]*"' | cut -d'"' -f4)
  echo "[ERROR] API请求失败" >&2
  echo "[ERROR] 错误信息: $ERROR_MSG" >&2
  echo "[ERROR] 请求ID: $REQUEST_ID" >&2
  echo "[ERROR] 诊断链接: https://api.aliyun.com/troubleshoot?q=IncompleteSignature&product=Rds&requestId=$REQUEST_ID" >&2
  exit 1
fi

openwrt配置

*/5 * * * * /usr/bin/update_rds_whitelist.sh

corn执行日志

0

评论区