跳转至

网络设计

一句话

一个包能不能到达服务器,要过三关:路由(有没有路)→ Security List / NSG(云上的防火墙让不让过)→ OS 的防火墙。 设计从"服务器不要公网 IP"出发:入口只留 LB,运维走 Bastion,出口按用途分开。

本页整理自 Phase 1、Phase 2、Phase 4、Phase 9 的实验。OKE 特有的网络(Pod 网络、API endpoint)在 Kubernetes 页。

1. 先认识这些组件

没碰过 OCI 的话,先对照 AWS 理解。名字不同,概念基本一样。

OCI AWS 一句话
VCN VPC 自己的私有网络,先定一个大的 CIDR(例:10.4.0.0/16)
Subnet Subnet VCN 切出来的一段。OCI 的 subnet 默认跨整个 region(AWS 是一个 AZ 一个)
public / private subnet 同左 OCI 用 prohibit_public_ip_on_vnic 区分:private subnet 里的 VM 不能有公网 IP
Route Table Route Table "去哪个目的地 → 交给哪个 Gateway",每个 subnet 绑一张
Internet Gateway(IGW) Internet Gateway 双向连 Internet。只有 public subnet 用
NAT Gateway NAT Gateway 只出不进:private 的 VM 可以下载东西,外面连不进来
Service Gateway(SGW) VPC Endpoint 不经过 Internet,走 Oracle 内部网络访问 OCI 的服务(Object Storage、ADB、dnf 仓库…)
Security List(SL) NACL(但 OCI 默认是 stateful) subnet 级的防火墙,subnet 里所有 VM 都受它影响
NSG Security Group VNIC(网卡)级的防火墙,只影响加入了这个 NSG 的 VM
Bastion SSM Session Manager(近似) 托管的跳板,从外面登录没有公网 IP 的 VM

2. 原理:一个包要过的三关

flowchart TB
  P["包"] --> R{"① 路由表<br/>有路吗?"}
  R -->|没有| D1["丢弃<br/>Flow Logs 里也没有"]
  R -->|有| S{"② Security List ∪ NSG<br/>有一个放行吗?"}
  S -->|都没放行| D2["拒绝<br/>Flow Logs:REJECT"]
  S -->|放行| F{"③ OS 防火墙<br/>端口开了吗?"}
  F -->|没开| D3["拒绝"]
  F -->|开了| OK["到达进程"]

① 路由决定"能不能到",安全规则决定"让不让进",两者互相独立。 安全规则全放行,没有路由照样不通;有路由,安全规则不放行也不通。

② Security List 和 NSG 是"并集"。 只要其中一个放行就能通,不是"两个都要放行"。

  • 后果:想用 NSG 精确限制的端口,SL 里就不能宽泛放行。 SL 放行了整个 VCN 的 22,NSG 再怎么写"只允许 Bastion"也没有用
  • AWS 正好相反:NACL 和 Security Group 是"两边都要放行"(交集)。从 AWS 转过来的人特别容易在这里栽跟头

③ 云上放行了,OS 里还有一道。 Oracle Linux 默认开着 firewalld,NSG 放行了 80,OS 不开也连不上。

补充两条规则:

  • stateful:OCI 的规则默认是 stateful,进来的连接,返回的包自动放行,不用另写规则。但"出站 / 入站"是从每块网卡的角度看的。例:Bastion 的 private endpoint 也在 VM 的 subnet 里,它 → VM:22 对 endpoint 来说是"出站",SL 的出站规则也要放行
  • 最长前缀匹配:一张路由表里 0.0.0.0/0 → NAT 和 Oracle 服务 → SGW 同时存在时,去 Oracle 服务的流量匹配更具体的那条,走 SGW

3. 出口:三种 Gateway 怎么选

需求 用 例子
外面要能连进来 Internet Gateway(IGW,只给 public subnet) LB 所在的 subnet
VM 要下载外部的东西,但不想被连进来 NAT Gateway(NAT GW) 装 pip 包、拉 Docker Hub 的镜像
VM 只访问 OCI 自己的服务 Service Gateway(SGW) dnf 仓库、Vault、Object Storage、ADB、监控 Agent
# private subnet 的路由表(Phase 4,简化:实际代码用 dynamic 块按开关生成):两条规则,各走各的 Gateway
route_rules {
  destination       = "0.0.0.0/0"
  network_entity_id = oci_core_nat_gateway.this[0].id      # 普通的 Internet → NAT
}
route_rules {
  destination       = data.oci_core_services.all[0].services[0].cidr_block  # "all-kix-services-in-oracle-services-network"
  destination_type  = "SERVICE_CIDR_BLOCK"                 # 目的地是"服务",IP 段由 OCI 维护
  network_entity_id = oci_core_service_gateway.this[0].id
}

最安全的组合:只有 Service Gateway(SGW)

Phase 9 的私有 VM 只有 Service Gateway,没有 Internet Gateway 和 NAT Gateway:dnf 装包、Vault 取密码、Agent 上报都正常,但完全出不了公网。不需要 Internet 的服务器,就不给它 NAT Gateway。

4. 访问控制:Security List(SL)和 NSG 怎么分工

Security List NSG
作用范围 subnet 里的所有 VM 加入了这个 NSG 的 VM
规则的来源 / 目的地 只能写 CIDR CIDR,或者另一个 NSG
适合放 整个 subnet 都需要的基本规则 按"层"(LB 层、app 层)写的业务规则

本仓库的做法:SL 只放最基本的,业务规则全写在 NSG 里,而且 NSG 之间互相引用。

# app 层只接受"来自 LB 层"的 80(Phase 4 security.tf)
resource "oci_core_network_security_group_security_rule" "app_http_from_lb" {
  network_security_group_id = oci_core_network_security_group.app.id
  direction                 = "INGRESS"
  protocol                  = "6"                                     # TCP
  source                    = oci_core_network_security_group.lb.id  # 来源写 NSG,不写 IP
  source_type               = "NETWORK_SECURITY_GROUP"
  tcp_options {
    destination_port_range {
      min = 80
      max = 80
    }
  }
}

来源写成"lb-nsg",LB 的 IP 变了、app VM 增减了,规则都不用改。

SL 里只留这两类:

  • ICMP type 3 code 4(Path MTU Discovery):路径上某段 MTU 较小时,靠这个 ICMP 通知发送方把包改小。挡掉的话大包会无声无息地丢掉。OCI 默认的 SL 里也有这一条
  • 出站全放行(出站的控制交给路由:没给 NAT 就出不去)

实际踩过的坑:SL 放行了整个 VCN 的 22

Phase 4 当初在 SL 里放行了"VCN 内 → 22",又在 NSG 里写了"22 只接受 Bastion",以为 SSH 只能从 Bastion 进来。 因为是并集,实际上 VCN 里谁都能连 22(例如 app-1 → app-2)。当时只测了"从 Bastion 能连上",没测"从别处连不上",所以没发现。 现在的代码已改成 SL 不放行 22,SSH 只由 NSG 控制(改完没有重新部署验证)。

5. 运维:怎么登录没有公网 IP 的服务器

方式 做法 用在 评价
公网 IP + SSH SL / NSG 放行本机 IP 的 22 — 所在网络屏蔽了 22,用不了;本来也是攻击面
Cloud Shell private network Cloud Shell 接进 VCN 的 subnet,拿到私有 IP 后直接 SSH Phase 2、Phase 6 简单。但 Cloud Shell 会在 subnet 里留一块网卡,destroy 前要切回 Public
OCI Bastion Cloud Shell → Bastion(session)→ VM:22 Phase 4、Phase 9 推荐。免费、托管(不用自己维护跳板机)、session 有时限、留审计记录
flowchart TB
  CS["Cloud Shell"] -->|"① 用 IAM 权限建 session<br/>登记 SSH 公钥<br/>最长 3 小时"| B["Bastion"]
  B -->|"② 经 private endpoint<br/>VCN 里的私有 IP"| VM["VM :22<br/>NSG 只接受 endpoint 的 IP"]

几个设计点:

  • NSG 的 SSH 来源写成 Bastion 的属性,不写死 IP:source = "${oci_bastion_bastion.this.private_endpoint_ip_address}/32"
  • session 不放进 Terraform:最长 3 小时就过期,放进去以后每次 plan 都有差异。用的时候在 Cloud Shell 里建
  • Bastion 的 client_cidr_block_allow_list 只能写 0.0.0.0/0:Cloud Shell 的出口 IP 不固定。这是有意识的取舍,安全性靠两样东西:建 session 要 IAM 权限,连接要 session 登记的私钥

为什么不直接放行 Cloud Shell 的公网 IP?

Cloud Shell 的出口 IP 是 Oracle 的共用 IP,而且会变。放行它,等于对其他 OCI 用户也开放了。

6. 设计决策一览

决策 选了 没选 理由
服务器放哪 private subnet,没有公网 IP public subnet + 公网 IP 公网 IP + 开着的端口 = 攻击面
外部访问的入口 只有 LB(在 public subnet) VM 直接公开 入口集中到一处,VM 可以增减、替换
安全规则的写法 NSG 按层建,互相引用 在规则里写 IP IP 变了、台数变了都不用改规则
SSH 的来源控制 只在 NSG 写 Bastion 的 IP SL 放行整个 VCN SL 和 NSG 是并集,SL 一宽泛 NSG 就失效
运维通道 OCI Bastion 自己建跳板 VM 免费、托管、不用打补丁、有审计记录
出口 按用途:NAT + SGW;不需要 Internet 的只给 SGW 统一走 NAT 访问 OCI 服务不经过 Internet;能少开就少开
访问 Always Free 的 ADB public endpoint + ACL(只允许本 VCN 和本机 IP),VCN 内经 SGW private endpoint Always Free ADB 不支持 private endpoint

7. 验证:怎么证明设计生效了

只验证"能通"不够,"不该通的确实不通"也要实际测一次。

要证明的事 正确的方法 不能当证据的
出 Internet 走的是 NAT VM 上 curl ifconfig.me → 显示 NAT GW 的公网 IP dnf install 成功(dnf 仓库属于 Oracle 服务,走的是 SGW)
完全出不了公网 curl -m 5 ifconfig.me → timeout Flow Logs 里有没有记录(没有路由的包不会出现在 Flow Logs 里,这是实验中观察到的)
访问 ADB 走的是 SGW 在 ADB 里查 sys_context('USERENV','IP_ADDRESS') → 是 VM 的私有 IP 能连上(走 NAT 也能连)
SSH 只能从 Bastion 进 从 Bastion 能登录 + 从 app-1 → app-2:22 会 timeout(本仓库当时没做这个反向测试,所以漏掉了问题) 只测了从 Bastion 能登录
规则真的和代码一致 用 API / Console 看实际的规则 plan 没报错

8. 坑

现象 原因 对策
NSG 写了"只允许 X",别的来源也能连 SL 和 NSG 是并集,SL 放行得太宽 SL 不放行要精确控制的端口;做反向测试
Bastion session 连不上 VM SL 只放行了出站 443,endpoint → VM:22 对 endpoint 是出站 SL 加"subnet 内 22 出站"
destroy 时 subnet 一直删不掉 Cloud Shell private network 的网卡还挂在 subnet 上 destroy 前把 Cloud Shell 的 Network 切回 Public;用 list_private_ips(subnet_id=...) 查是谁
dnf install 成功,以为 NAT 通了 dnf 仓库走 SGW 用 curl ifconfig.me 看出口 IP
从本机 SSH timeout 所在网络屏蔽出站 22 用 Cloud Shell(private network 或 Bastion)

9. 自测问题

1. VM 的 SL 放行了 22,NSG 没放行 22,从 VCN 内能 SSH 吗?

能。SL 和 NSG 是并集,有一个放行就能通。

2. 同样的配置换到 AWS(NACL 放行、Security Group 没放行),能连吗?

不能。AWS 的 NACL 和 Security Group 两边都要放行。

3. private subnet 的 VM 能 dnf install,能说明 NAT GW 配好了吗?

不能。OCI 的 dnf 仓库属于 Oracle 服务,有 SGW 就能装。要用 curl ifconfig.me 看出口 IP 是不是 NAT 的公网 IP。

4. 一台 VM 只需要从 Vault 取密码、往 Object Storage 写日志,出口该怎么配?

只给 SGW,不给 NAT 和 IGW。这样它访问 OCI 服务没问题,但完全出不了公网。

5. app-nsg 的 80 端口,来源为什么写 lb-nsg 而不写 LB 的 IP?

LB 的 IP 可能变,app VM 也可能增减。写 NSG 的话规则不用改,而且规则本身就说明了"只有 LB 层能访问 app 层"。

6. Bastion 的 client_cidr_block_allow_list 是 0.0.0.0/0,安全吗?

这是取舍:Cloud Shell 的出口 IP 不固定,没法限定来源。安全靠建 session 需要 IAM 权限、连接需要 session 登记的私钥,而且 session 最长 3 小时。如果客户端 IP 固定,就应该限定。

7. 怎么证明「SSH 只能从 Bastion 进来」?

两个方向都要测:从 Bastion 能登录(正向),从 VCN 里其他 VM 连 22 会 timeout(反向)。只测正向的话,SL 放行过宽这种问题发现不了。

8. 路由表里同时有 0.0.0.0/0 → NAT 和 Oracle 服务 → SGW,访问 Object Storage 走哪个?

走 SGW。路由按最长前缀匹配,Oracle 服务的地址段比 0.0.0.0/0 更具体。

完整代码

正文只摘了关键部分。完整代码(Phase 4 的 3 层结构):

04-3tier/modules/network/main.tf(VCN / Gateway / 路由表 / SL / subnet)
# ------------------------------------------------------------
# network module:VCN 一套(Phase 4 版)
#   VCN ─ Internet Gateway / NAT Gateway / Service Gateway
#    ├─ Public Subnet(s)  ─ rt-public (0.0.0.0/0 → IGW)
#    └─ Private Subnet(s) ─ rt-private(0.0.0.0/0 → NAT GW、Oracle Services → Service GW)
#   Security List 所有 Subnet 共用一个
# 和 03 的区别:
#   - 加了 NAT GW / Service GW(用 bool 开关,count 控制建不建)
#   - Private Subnet 不再用 VCN 的默认 Route Table,改用自己建的 rt-private
# ------------------------------------------------------------

locals {
  # for_each 的表达式:按 is_public 把 Subnet 分成两组
  public_subnets  = { for k, s in var.subnets : k => s if s.is_public }
  private_subnets = { for k, s in var.subnets : k => s if !s.is_public }

  create_nat = var.enable_nat_gateway && length(local.private_subnets) > 0
  create_sgw = var.enable_service_gateway && length(local.private_subnets) > 0
}

resource "oci_core_vcn" "this" {
  compartment_id = var.compartment_ocid
  cidr_blocks    = [var.vcn_cidr]
  display_name   = "${var.name_prefix}-vcn"
  dns_label      = var.vcn_dns_label

  freeform_tags = var.freeform_tags
}

# ---- Gateway ----

# Public Subnet 一个都没有的话就不需要 IGW → count 控制建 0 个还是 1 个
resource "oci_core_internet_gateway" "this" {
  count = length(local.public_subnets) > 0 ? 1 : 0

  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.this.id
  display_name   = "${var.name_prefix}-igw"
  enabled        = true

  freeform_tags = var.freeform_tags
}

# NAT GW:Private Subnet 里的 VM 只能"从里往外"连 Internet(外面连不进来)
#   用途:dnf install、OS 更新等
resource "oci_core_nat_gateway" "this" {
  count = local.create_nat ? 1 : 0

  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.this.id
  display_name   = "${var.name_prefix}-natgw"

  freeform_tags = var.freeform_tags
}

# Service GW 的连接对象:"All <region> Services In Oracle Services Network"
#   (另一个选项是只有 Object Storage 的那个。ADB 要用 All 的这个)
data "oci_core_services" "all" {
  count = local.create_sgw ? 1 : 0

  filter {
    name   = "name"
    values = ["All .* Services In Oracle Services Network"]
    regex  = true
  }
}

# Service GW:不经过 Internet,直接走 Oracle 内部网络访问 OCI 的服务(ADB、Object Storage 等)
resource "oci_core_service_gateway" "this" {
  count = local.create_sgw ? 1 : 0

  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.this.id
  display_name   = "${var.name_prefix}-sgw"

  services {
    service_id = data.oci_core_services.all[0].services[0].id
  }

  freeform_tags = var.freeform_tags
}

# ---- Route Table ----

resource "oci_core_route_table" "public" {
  count = length(local.public_subnets) > 0 ? 1 : 0

  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.this.id
  display_name   = "${var.name_prefix}-rt-public"

  route_rules {
    destination       = "0.0.0.0/0"
    destination_type  = "CIDR_BLOCK"
    network_entity_id = oci_core_internet_gateway.this[0].id # count 建的资源要用 [0] 引用
  }

  freeform_tags = var.freeform_tags
}

# Private 用的 Route Table:NAT / SGW 有几个开着就生成几条规则
#   Oracle Services 的流量会匹配更具体的 SGW 规则,不会走 NAT(最长前缀匹配)
resource "oci_core_route_table" "private" {
  count = length(local.private_subnets) > 0 ? 1 : 0

  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.this.id
  display_name   = "${var.name_prefix}-rt-private"

  dynamic "route_rules" {
    for_each = local.create_nat ? [1] : []
    content {
      destination       = "0.0.0.0/0"
      destination_type  = "CIDR_BLOCK"
      network_entity_id = oci_core_nat_gateway.this[0].id
    }
  }

  dynamic "route_rules" {
    for_each = local.create_sgw ? [1] : []
    content {
      # 目的地不是 CIDR,而是"服务"(例:all-kix-services-in-oracle-services-network)
      destination       = data.oci_core_services.all[0].services[0].cidr_block
      destination_type  = "SERVICE_CIDR_BLOCK"
      network_entity_id = oci_core_service_gateway.this[0].id
    }
  }

  freeform_tags = var.freeform_tags
}

# ---- Security List ----

resource "oci_core_security_list" "this" {
  compartment_id = var.compartment_ocid
  vcn_id         = oci_core_vcn.this.id
  display_name   = "${var.name_prefix}-sl"

  egress_security_rules {
    destination = "0.0.0.0/0"
    protocol    = "all"
  }

  # dynamic block:var.ssh_allowed_cidrs 有几个就生成几条规则
  dynamic "ingress_security_rules" {
    for_each = var.ssh_allowed_cidrs
    content {
      source      = ingress_security_rules.value
      protocol    = "6"
      description = "SSH"
      tcp_options {
        min = 22
        max = 22
      }
    }
  }

  # ICMP type 3 code 4(Path MTU Discovery)
  ingress_security_rules {
    source   = "0.0.0.0/0"
    protocol = "1"
    icmp_options {
      type = 3
      code = 4
    }
  }

  freeform_tags = var.freeform_tags
}

# ---- Subnet ----

# for_each:var.subnets 的每个条目建一个 Subnet
#   state 里是 oci_core_subnet.this["public"] 这样的地址
resource "oci_core_subnet" "this" {
  for_each = var.subnets

  compartment_id    = var.compartment_ocid
  vcn_id            = oci_core_vcn.this.id
  cidr_block        = each.value.cidr
  display_name      = "${var.name_prefix}-subnet-${each.key}"
  dns_label         = each.value.dns_label
  security_list_ids = [oci_core_security_list.this.id]

  route_table_id             = each.value.is_public ? oci_core_route_table.public[0].id : oci_core_route_table.private[0].id
  prohibit_public_ip_on_vnic = !each.value.is_public

  freeform_tags = var.freeform_tags
}
04-3tier/env/security.tf(NSG)
# ------------------------------------------------------------
# NSG:按"层"建,同一层的 VM 共用
#   lb-nsg :LB
#   app-nsg:app VM ×2
#   规则里可以写"来源/目的地 = 另一个 NSG"(source_type = NETWORK_SECURITY_GROUP)
#   → 不用写 IP,VM 增减、IP 变化都不用改规则
#
#   my_ip ──:80──→ [lb-nsg] LB ──:80──→ [app-nsg] VM ×2 ←──:22── Bastion
#
# checkov CKV_OCI_21(要求 ingress 规则用 stateless)→ 有意不改,在各规则里用 skip 注释写明理由
#   stateless = 不记录连接状态,返回流量要另写规则放行(规则翻倍、易配错);优点是大流量时性能好
#   这里流量很小,用默认的 stateful
# ------------------------------------------------------------

# ---- lb-nsg ----

resource "oci_core_network_security_group" "lb" {
  compartment_id = var.compartment_ocid
  vcn_id         = module.network.vcn_id
  display_name   = "${local.name_prefix}-lb-nsg"

  freeform_tags = local.common_tags
}

# 入:只允许本机的 IP 访问 LB 的 80
resource "oci_core_network_security_group_security_rule" "lb_http_from_my_ip" {
  #checkov:skip=CKV_OCI_21:Low traffic lab; stateful rules are simpler and sufficient
  network_security_group_id = oci_core_network_security_group.lb.id
  direction                 = "INGRESS"
  protocol                  = "6"
  source                    = "${var.my_ip}/32"
  source_type               = "CIDR_BLOCK"
  description               = "HTTP from my IP"

  tcp_options {
    destination_port_range {
      min = 80
      max = 80
    }
  }
}

# 出:LB → app VM 的 80(转发请求 + 健康检查)
#   (Subnet 的 Security List 已经允许全部出站,这条不写也能通。写出来是为了让 NSG 自己就能说明"LB 只往 app 发")
resource "oci_core_network_security_group_security_rule" "lb_http_to_app" {
  network_security_group_id = oci_core_network_security_group.lb.id
  direction                 = "EGRESS"
  protocol                  = "6"
  destination               = oci_core_network_security_group.app.id
  destination_type          = "NETWORK_SECURITY_GROUP"
  description               = "HTTP to app"

  tcp_options {
    destination_port_range {
      min = 80
      max = 80
    }
  }
}

# ---- app-nsg ----

resource "oci_core_network_security_group" "app" {
  compartment_id = var.compartment_ocid
  vcn_id         = module.network.vcn_id
  display_name   = "${local.name_prefix}-app-nsg"

  freeform_tags = local.common_tags
}

# SSH 只接受 Bastion 来的连接
#   Bastion 在 app Subnet 里有一个 private endpoint(私有 IP),SSH 会从这个 IP 进来
resource "oci_core_network_security_group_security_rule" "app_ssh_from_bastion" {
  #checkov:skip=CKV_OCI_21:Low traffic lab; stateful rules are simpler and sufficient
  network_security_group_id = oci_core_network_security_group.app.id
  direction                 = "INGRESS"
  protocol                  = "6"
  source                    = "${oci_bastion_bastion.this.private_endpoint_ip_address}/32"
  source_type               = "CIDR_BLOCK"
  description               = "SSH from Bastion"

  tcp_options {
    destination_port_range {
      min = 22
      max = 22
    }
  }
}

# HTTP 只接受 LB 来的连接(来源写 lb-nsg,不写 IP)
#   app VM 之间、Bastion → VM 的 80 仍然不通
resource "oci_core_network_security_group_security_rule" "app_http_from_lb" {
  #checkov:skip=CKV_OCI_21:Low traffic lab; stateful rules are simpler and sufficient
  network_security_group_id = oci_core_network_security_group.app.id
  direction                 = "INGRESS"
  protocol                  = "6"
  source                    = oci_core_network_security_group.lb.id
  source_type               = "NETWORK_SECURITY_GROUP"
  description               = "HTTP from LB"

  tcp_options {
    destination_port_range {
      min = 80
      max = 80
    }
  }
}
04-3tier/env/bastion.tf
# ------------------------------------------------------------
# OCI Bastion Service(Always Free)
#   跳板机由 OCI 托管,不用自己建 VM、打补丁
#   Terraform 只建 Bastion 本体;session(有效期最长 3 小时)每次用的时候在 Console / CLI 里建
#   → session 放进 Terraform 的话,过期后每次 plan 都会出差异
# ------------------------------------------------------------

resource "oci_bastion_bastion" "this" {
  compartment_id   = var.compartment_ocid
  bastion_type     = "STANDARD"
  name             = "${local.name_prefix}bastion" # 只能用字母和数字(不能有 -)
  target_subnet_id = module.network.subnet_ids["app"]

  # 允许连 Bastion 的来源
  #   所在网络屏蔽 22 → 实际从 Cloud Shell 连,而 Cloud Shell 的公网 IP 不固定 → 只能 0.0.0.0/0
  #   安全性靠 session:要有 IAM 权限才能建 session,而且只认建 session 时登记的 SSH 公钥
  client_cidr_block_allow_list = ["0.0.0.0/0"]

  max_session_ttl_in_seconds = 10800 # 3 小时(上限)

  freeform_tags = local.common_tags
}