Posted in

Go语言扫描器接入SIEM全流程(Splunk ES / Elastic Security / Microsoft Sentinel对接模板)

第一章:Go语言网络扫描器设计概览

网络扫描器是网络安全评估与基础设施探测的核心工具,Go语言凭借其并发模型、跨平台编译能力及简洁高效的语法,成为构建高性能扫描器的理想选择。本章聚焦于设计原则与架构选型,不涉及具体漏洞检测逻辑,而是为后续模块化实现奠定基础。

核心设计目标

  • 高并发可控性:利用 goroutine 与 channel 实现连接池管理,避免资源耗尽;
  • 协议可扩展性:采用接口抽象(如 ScannerProbe),支持 TCP、ICMP、HTTP 等多种探测方式;
  • 结果结构化输出:统一返回 ScanResult 结构体,包含目标地址、端口、状态码、响应头等字段;
  • 低侵入性与合规性:默认启用速率限制(如每秒最多 100 个连接)、超时控制(默认 3 秒)及用户代理标识。

关键组件职责划分

组件 职责说明
TargetParser 解析 CIDR、域名、IP 列表等输入,生成标准化目标集
PortManager 提供常用端口列表(如 []int{22, 80, 443, 8080})及自定义端口范围支持
ProbeEngine 封装底层探测逻辑(如 net.DialTimeouthttp.Get),处理重试与错误分类
ResultAggregator 汇总并去重扫描结果,支持 JSON/CSV 输出格式

快速启动示例

以下代码片段展示最简 TCP 端口探测核心逻辑(含超时与错误处理):

func probeTCP(target string, port int, timeout time.Duration) (bool, error) {
    addr := fmt.Sprintf("%s:%d", target, port)
    conn, err := net.DialTimeout("tcp", addr, timeout)
    if err != nil {
        // 区分连接拒绝(端口关闭)与超时/无路由(网络不可达)
        if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
            return false, fmt.Errorf("timeout")
        }
        return false, fmt.Errorf("connection refused or unreachable")
    }
    defer conn.Close()
    return true, nil
}

该函数可被 ProbeEngine 并发调用,配合 sync.WaitGroupcontext.WithTimeout 实现全局扫描时限控制。

第二章:Go扫描器核心模块实现

2.1 基于net包的TCP/UDP端口探测与并发控制实践

核心探测逻辑

Go 的 net.DialTimeout 是实现轻量级端口探测的基石,支持 TCP/UDP 协议抽象,无需手动构造底层 socket。

func probePort(host string, port int, proto string, timeout time.Duration) bool {
    conn, err := net.DialTimeout(proto, fmt.Sprintf("%s:%d", host, port), timeout)
    if err != nil {
        return false
    }
    conn.Close()
    return true
}

逻辑分析:proto 可为 "tcp""udp"timeout 避免阻塞(建议 ≤ 500ms);UDP 探测实际发送空数据包并等待 ICMP 端口不可达或超时,故结果为“可达性暗示”而非严格连接确认。

并发安全控制

使用 semaphore 限流 + errgroup 统一错误管理:

控制维度 推荐值 说明
并发数 32–128 平衡探测吞吐与系统资源
超时 300ms 防止单点拖慢整体扫描
重试 1 次 规避瞬时网络抖动

扫描流程示意

graph TD
    A[启动扫描] --> B[获取目标端口列表]
    B --> C[按信号量获取协程许可]
    C --> D[执行 DialTimeout 探测]
    D --> E{成功?}
    E -->|是| F[记录开放端口]
    E -->|否| G[跳过]
    F & G --> H[等待全部完成]

2.2 使用golang.org/x/net/icmp构建ICMP扫描器并规避内核限速

原生ICMP套接字的权限与初始化

CAP_NET_RAW能力或root权限创建原始套接字。使用icmp.ListenPacket建立连接,并显式指定IPv4协议族:

conn, err := icmp.ListenPacket(iana.ProtocolICMP, 0)
if err != nil {
    log.Fatal(err) // 如无权限将返回 "operation not permitted"
}
defer conn.Close()

iana.ProtocolICMP(值为1)确保使用标准ICMP协议号;表示由内核自动分配源端口(对ICMP无效,但API要求)。该调用底层执行socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)

规避内核限速的关键:套接字选项调优

Linux内核默认对icmp_echo实施速率限制(net.ipv4.icmp_ratelimit,默认1000/ms)。可通过以下方式绕过:

  • 设置SO_PRIORITY提升套接字优先级
  • 使用SetReadBuffer/SetWriteBuffer增大缓冲区减少丢包
  • 关闭ICMP_ECHO限速(需root修改sysctl -w net.ipv4.icmp_ratelimit=0
选项 作用 推荐值
net.ipv4.icmp_echo_ignore_all 全局禁用响应 (保持响应)
net.ipv4.icmp_ratelimit 每秒允许响应数 (禁用限速)
net.ipv4.ping_group_range 允许非root用户发送 0 2147483647

并发控制与探测节奏

采用带缓冲channel控制并发ICMP请求量,避免触发内核背压:

sem := make(chan struct{}, 32) // 限流32并发
for _, ip := range targets {
    sem <- struct{}{}
    go func(ip net.IP) {
        defer func() { <-sem }()
        sendEchoRequest(conn, ip)
    }(ip)
}

channel容量即并发上限,防止瞬时大量sendto()系统调用引发ENOBUFS错误。

2.3 HTTP/S服务指纹识别:User-Agent协商、TLS指纹与响应特征提取

HTTP/S服务指纹识别是资产测绘与威胁情报的关键环节,融合协议层与应用层多维特征。

User-Agent 协商行为分析

客户端主动声明能力,但易被伪造。真实指纹需结合服务端响应反推:

import requests
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
resp = requests.get("https://example.com", headers=headers, timeout=5)
# 分析 Server、X-Powered-By、Strict-Transport-Security 等响应头组合

该请求模拟主流浏览器UA,但关键在于响应头中Server: nginx/1.22.1X-Content-Type-Options: nosniff的共现模式,构成轻量级服务指纹锚点。

TLS指纹提取维度

TLS握手参数具备强设备/栈特征:

字段 典型值 指纹意义
ALPN h2,http/1.1 表明支持HTTP/2
SNI example.com 揭示虚拟主机配置
Cipher Suites TLS_AES_128_GCM_SHA256 暗示OpenSSL 1.1.1+或BoringSSL

响应特征联合建模

graph TD
    A[HTTP请求] --> B[TLS握手]
    B --> C[HTTP响应头解析]
    C --> D[状态码+Body长度+HTML标题标签]
    D --> E[聚类生成服务指纹]

现代指纹引擎依赖三者交叉验证——单一维度误报率高,而组合特征可区分Nginx/OpenResty、Apache+mod_ssl、Cloudflare边缘节点等典型栈。

2.4 主机发现与ARP/ICMP/HTTP多层存活判定策略落地

多协议协同判定逻辑

单一协议易受防火墙或策略干扰:ARP适用于局域网二层可达性验证,ICMP提供三层连通性反馈,HTTP则进一步确认应用层服务活性。三者按「快速→可靠→语义」分层递进。

判定优先级与超时配置

  • ARP探测(毫秒级):timeout=100ms,失败即跳过本子网其他主机
  • ICMP探测(中速):count=3, interval=500ms,丢包率>66%视为不可达
  • HTTP探测(精准):仅对开放80/443端口发起HEAD /healthz请求,timeout=3s

实现示例(Python片段)

def multi_layer_probe(ip):
    if arp_check(ip):           # 发送ARP请求并解析响应MAC
        if icmp_check(ip):      # 发送ICMP Echo Request
            return http_check(ip, "/healthz")  # TLS握手+HEAD请求
    return False

arp_check()底层调用scapy.sendp()构造ARP帧;icmp_check()基于icmplib.ping()避免root依赖;http_check()使用requests.Session()复用连接并设置verify=False兼容自签名证书。

协议判定结果映射表

协议 成功标志 常见失败原因
ARP 收到ARP Reply 主机关机、交换机ACL拦截
ICMP Echo Reply ≥1 防火墙禁ping、主机禁ICMP
HTTP status_code=200 Web服务未启、路径不存在、TLS握手失败
graph TD
    A[启动探测] --> B{ARP可达?}
    B -->|是| C{ICMP响应?}
    B -->|否| D[标记L2不可达]
    C -->|是| E{HTTP健康端点返回200?}
    C -->|否| F[标记L3不可达]
    E -->|是| G[标记全栈存活]
    E -->|否| H[标记L7异常]

2.5 扫描任务调度引擎:基于channel+context的超时、重试与限速机制

核心设计思想

context.Context 统一传递取消信号与截止时间,用 chan struct{} 协调任务生命周期,避免 goroutine 泄漏。

超时控制实现

ctx, cancel := context.WithTimeout(parentCtx, 30*time.Second)
defer cancel()

select {
case <-doneChan:
    return result
case <-ctx.Done():
    return nil, ctx.Err() // 自动携带 DeadlineExceeded
}

WithTimeout 生成可取消上下文;ctx.Done() 在超时或手动取消时关闭,驱动 select 退出;ctx.Err() 精确返回超时原因。

限速与重试协同策略

机制 实现方式 触发条件
限速 time.Sleep(rateLimiter.Next()) 每次任务执行前阻塞
指数退避重试 backoff := time.Second << uint(attempt) HTTP 5xx 或网络错误

任务调度流程

graph TD
    A[新任务入队] --> B{是否超限?}
    B -- 是 --> C[阻塞等待令牌]
    B -- 否 --> D[启动goroutine]
    D --> E[WithContext执行]
    E --> F{成功?}
    F -- 否 --> G[按策略重试]
    F -- 是 --> H[释放资源]

第三章:SIEM日志标准化与传输协议适配

3.1 CEF/NXLog/Syslog格式转换:Go结构体序列化与字段映射规则

字段映射核心原则

CEF、NXLog与Syslog虽共享时间戳、主机名等基础字段,但语义层级与分隔符差异显著:

  • CEF:CEF:0|Vendor|Product|Version|SignatureID|Name|Severity|ext= + 键值对
  • Syslog RFC5424:<PRI>VERSION TIMESTAMP HOSTNAME APPNAME PROCID MSGID STRUCTURED-DATA MSG
  • NXLog:支持自定义字段(如 $EventReceivedTime, $SourceName

Go结构体设计示例

type LogEntry struct {
    Timestamp     time.Time `json:"time" cef:"startTime"`          // CEF要求毫秒级ISO8601,Syslog需RFC3339
    Hostname      string    `json:"host" cef:"deviceHostName"`      // CEF字段名映射,Syslog直接使用hostname
    Severity      int       `json:"severity" cef:"severity"`        // CEF 0–10,Syslog 0–7 → 需缩放转换
    Extension     map[string]string `json:"ext" cef:"-"`            // CEF专用扩展字段,Syslog转为SD-PARAM
}

逻辑分析cef标签指定目标格式字段名;-表示该字段不参与CEF序列化;time.TimeMarshalJSON()自动转RFC3339,而CEF要求startTime=2024-05-20T10:30:45.123Z,需自定义MarshalText()适配。

映射规则对照表

源字段 CEF目标字段 Syslog位置 转换逻辑
LogEntry.Severity severity priority (Prio) syslogPri := (Severity/2)<<3
LogEntry.Extension["src_ip"] sourceAddress SD-PARAM src_ip="..." 键名重映射 + 值URL编码

数据同步机制

graph TD
A[原始日志] --> B{解析为LogEntry}
B --> C[CEF序列化]
B --> D[Syslog序列化]
B --> E[NXLog序列化]
C --> F[cef.StartTime = entry.Timestamp.UTC().Format(time.RFC3339Nano)]
D --> G[syslog.Msg = fmt.Sprintf("<%d>%d %s %s %s - - - %s", priority, ...)]

字段映射依赖运行时标签反射,encoding/json与自定义MarshalCEF()协同完成协议适配。

3.2 Splunk HEC API对接:Token认证、批量事件提交与错误重放队列

Token认证机制

HEC(HTTP Event Collector)要求每个请求携带Authorization: Splunk <token>头。Token在Splunk Web中生成,具备细粒度权限控制(如索引写入、指定源类型限制)。

批量事件提交最佳实践

单次POST可携带最多10,000条事件(推荐≤1,000条以平衡吞吐与失败影响):

import requests
import json

url = "https://splunk.example.com:8088/services/collector"
headers = {"Authorization": "Splunk abc123-def456"}
events = [
    {"event": "user_login", "host": "web01", "fields": {"status": "success"}},
    {"event": "db_query", "host": "app02", "fields": {"duration_ms": 142}}
]
payload = {"events": events}

# 启用gzip压缩提升传输效率
response = requests.post(
    url, 
    headers=headers, 
    data=json.dumps(payload), 
    verify=True  # 生产环境务必启用SSL校验
)

逻辑说明:verify=True强制证书校验防止中间人攻击;data而非json=参数确保手动控制序列化(兼容特殊字段如_time);事件数组嵌套在"events"键下为HEC必需结构。

错误重放队列设计

当HTTP状态码非200(如429 Too Many Requests503 Service Unavailable)时,需本地暂存失败批次并指数退避重试。

状态码 建议动作 重试间隔
400 校验事件格式 终止重试
401 刷新Token 立即重试
429 指数退避+限流 1s → 2s → 4s
graph TD
    A[发送事件批次] --> B{HTTP响应?}
    B -->|200 OK| C[确认提交]
    B -->|4xx/5xx| D[加入内存队列]
    D --> E[指数退避调度]
    E --> F[重试或丢弃]

3.3 Elastic Security ECS Schema兼容性封装:Go类型到ECS字段的自动对齐

为统一安全事件建模,需将自定义Go结构体无缝映射至Elastic Common Schema(ECS)标准字段。核心在于字段命名规范、类型适配与嵌套路径解析。

字段映射策略

  • 自动将 ThreatIndicatorthreat.indicator
  • Timestamp@timestamp(ISO8601格式强制转换)
  • 嵌套结构如 Network.Protocolnetwork.protocol

核心映射代码示例

type Alert struct {
    Severity   int    `ecs:"event.severity"`     // 映射至ECS event.severity(整数)
    SourceIP   string `ecs:"source.ip"`          // 直接映射 source.ip
    ThreatType string `ecs:"threat.type"`        // threat.type 支持 "malware", "phishing"
}

// 自动生成ECS兼容map
func (a Alert) ToECS() map[string]interface{} {
    m := make(map[string]interface{})
    val := reflect.ValueOf(a).Elem()
    typ := reflect.TypeOf(a).Elem()
    for i := 0; i < val.NumField(); i++ {
        tag := typ.Field(i).Tag.Get("ecs")
        if tag != "" {
            m[tag] = val.Field(i).Interface()
        }
    }
    return m
}

逻辑分析:利用Go反射遍历结构体字段,提取ecs标签作为目标ECS字段路径;event.severity等标签值直接作为键名,避免硬编码路径拼接;所有值保留原始类型,由Elasticsearch动态映射处理。

典型字段对照表

Go字段名 ECS字段路径 类型约束
SourceIP source.ip IPv4/IPv6字符串
Severity event.severity integer (0–100)
ThreatType threat.type keyword
graph TD
    A[Go Struct] --> B{反射解析 ecs tag}
    B --> C[字段名 → ECS路径]
    C --> D[类型校验与标准化]
    D --> E[ECS-compliant map]

第四章:主流SIEM平台集成模板开发

4.1 Splunk ES接入模板:TA配置、KV Store状态管理与Threat Intelligence联动

TA配置核心结构

default/inputs.conf 中定义数据采集入口,关键字段需匹配ES事件模型:

[script://./bin/get_ioc_feed.py]
interval = 300
sourcetype = threat_intel:feed
index = es_threats
disabled = 0

interval=300 控制IOC更新频率;sourcetype 必须与ES Correlation Search中eventtype匹配,否则无法触发威胁匹配。

KV Store状态管理

使用collections.conf声明状态集合:

[threat_intel_status]
field.order = last_updated,feed_name,active_count

该配置确保| inputlookup threat_intel_status可精准返回最新IOC同步状态,支撑增量拉取逻辑。

Threat Intelligence联动流程

graph TD
A[TA定时执行脚本] --> B[解析STIX/TAXII源]
B --> C[写入KV Store校验状态]
C --> D[触发ES Threat Match Rule]
D --> E[生成Notable Event]
字段名 类型 用途
ioc_value string IP/Domain/Hash值
confidence number 0–100,影响ES风险评分
last_seen epoch 触发时效性告警的关键时间

4.2 Elastic Security集成模板:Detection Rule触发器对接与Alerts API双向同步

数据同步机制

Elastic Security通过alerts索引与Detection Engine规则联动,实现事件检测→告警生成→外部系统响应的闭环。关键在于alert_idrule_id的语义绑定及status字段状态机管理(open/acknowledged/closed)。

触发器对接逻辑

Detection Rule启用后,自动注册Webhook触发器,将signal文档推送至指定端点:

{
  "rule_id": "critical-login-fail",
  "alert_id": "a1b2c3d4",
  "status": "open",
  "signal_time": "2024-06-15T08:22:10.123Z"
}

此payload由Elastic Security自动生成,其中alert_id为全局唯一标识,signal_time用于时序对齐;接收端须返回HTTP 200确认,否则触发重试策略(指数退避,最大3次)。

双向同步协议

通过Alerts API实现状态反写:

方法 路径 用途
POST /api/detection_engine/alerts/status 批量更新告警状态
GET /api/detection_engine/alerts?status=open 拉取待处理告警
graph TD
  A[Detection Rule匹配] --> B[生成signal文档]
  B --> C[触发Webhook推送]
  C --> D[外部系统处理]
  D --> E[调用Alerts API更新status]
  E --> F[同步至Kibana Alerts UI]

4.3 Microsoft Sentinel Connector开发:Azure REST API鉴权、Common Alert Schema映射与Playbook触发钩子

Azure REST API 鉴权(Managed Identity + OAuth2)

Sentinel Connector 通常以 Azure Function 或 Logic App 为载体,推荐使用系统分配的托管标识(Managed Identity)获取 https://management.azure.com/ 范围的访问令牌:

import requests
from azure.identity import ManagedIdentityCredential

credential = ManagedIdentityCredential()
token = credential.get_token("https://management.azure.com/.default")
headers = {
    "Authorization": f"Bearer {token.token}",
    "Content-Type": "application/json"
}

逻辑分析ManagedIdentityCredential 自动从 IMDS(169.254.169.254)获取令牌,避免硬编码密钥;.default scope 表示使用 Azure Resource Manager 的默认权限集;token.token 是原始 JWT 字符串,不可解析后重用。

Common Alert Schema 映射关键字段

Sentinel 字段 原始告警字段(示例) 映射说明
alertName rule_name 必填,用于仪表板聚合
description details.message 支持 Markdown 渲染
severity levelHigh/Medium/Low 需标准化为 High, Medium, Low, Informational

Playbook 触发钩子设计

POST https://prod-XX.westus.logic.azure.com:443/workflows/abc123/triggers/manual/paths/invoke?api-version=2016-10-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=...
Content-Type: application/json

{
  "alertId": "resourceId:...",
  "incidentUrl": "https://sentinel.azure.com/.../incidents/..."
}

参数说明api-version 必须匹配 Logic App 运行时版本;sig 由 Logic App 生成并定期轮换;incidentUrl 供 Playbook 调用 Graph API 关联实体。

graph TD
    A[Connector接收原始告警] --> B[JWT鉴权调用ARM API]
    B --> C[转换为CAS JSON]
    C --> D[调用Sentinel API /alerts]
    D --> E[触发预注册Playbook]

4.4 多SIEM统一抽象层设计:Provider接口定义与运行时动态插件加载机制

为解耦底层SIEM差异,抽象出 Provider 接口作为统一接入契约:

public interface Provider {
    String id();                    // 唯一标识(如 "splunk-v4", "elastic-soar")
    boolean supports(EventType type); // 支持的事件类型枚举
    CompletableFuture<Alert> ingest(Alert raw); // 异步标准化写入
    Stream<Alert> search(Query q);   // 流式查询结果
}

该接口屏蔽了认证、协议(REST/gRPC/Syslog)、字段映射等实现细节,使上层编排逻辑完全无感。

运行时插件加载流程

采用 Java SPI + 自定义 ClassLoader 实现热插拔:

graph TD
    A[启动扫描 /plugins/*.jar] --> B[解析 META-INF/services/com.example.Provider]
    B --> C[实例化 Provider 实现类]
    C --> D[注册至 ProviderRegistry]
    D --> E[按 id 动态路由请求]

关键能力支撑

  • ✅ 插件隔离:每个 Provider 运行于独立类加载器,避免依赖冲突
  • ✅ 策略路由:通过 ProviderSelector 按标签(region/sec-level)匹配最优实例
  • ✅ 健康探测:启动后自动执行 healthCheck() 并加入服务发现
特性 Provider A Provider B 统一层表现
认证方式 API Key OAuth2 自动注入凭据上下文
时间字段名 _time @timestamp 映射为标准 eventTime
告警状态字段 severity level 归一为 SeverityEnum

第五章:生产环境部署与安全合规考量

部署拓扑与基础设施隔离

典型金融级生产环境采用三网分离架构:前端DMZ区承载HTTPS入口(Nginx反向代理),应用核心区运行Kubernetes集群(Calico CNI启用网络策略),数据持久层部署在物理隔离的私有子网中,数据库仅允许来自应用节点IP段的3306端口访问。以下为某支付系统实际落地的VPC路由表片段:

目标CIDR 下一跳类型 关联资源ID 路由策略
10.1.0.0/16 Local vpc-0a1b2c3d 主路由
0.0.0.0/0 NAT Gateway nat-gw-789efgh 出向流量
10.2.10.0/24 Interface eni-456ijk 数据库白名单

容器镜像可信供应链实践

某电商中台项目强制执行镜像签名验证流程:CI流水线使用Cosign对Docker镜像签名后推送至Harbor私有仓库;K8s集群通过Kyverno策略控制器拦截未签名或签名失效的Pod部署请求。关键策略配置如下:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-image-signature
spec:
  validationFailureAction: enforce
  rules:
  - name: check-signature
    match:
      any:
      - resources:
          kinds:
          - Pod
    verifyImages:
    - image: "registry.example.com/*"
      key: |-
        -----BEGIN PUBLIC KEY-----
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu...
        -----END PUBLIC KEY-----

GDPR与等保2.0双轨合规控制点

在用户数据处理模块中,同时满足欧盟GDPR“被遗忘权”与国内等保2.0三级要求:

  • 日志脱敏:Filebeat采集日志时通过dissect插件剥离手机号(正则(?<phone>\d{3})\d{4}(?<tail>\d{4})XXX****${tail}
  • 数据留存:MySQL审计日志设置log_statement = 'mod'且自动清理周期设为180天(SET GLOBAL audit_log_rotate_on_size=1073741824;
  • 加密传输:TLS 1.3强制启用,禁用所有弱密码套件(OpenSSL配置CipherString = DEFAULT@SECLEVEL=2

生产变更灰度发布机制

采用Argo Rollouts实现金丝雀发布:将新版本v2.1.3部署至5%流量切片,持续监控Prometheus指标(HTTP 5xx错误率>0.5%或P95延迟>800ms触发自动回滚)。下图为某风控服务灰度期间的流量分配状态图:

graph LR
    A[Ingress Controller] -->|100%流量| B[Service Router]
    B -->|5%| C[Deployment v2.1.3]
    B -->|95%| D[Deployment v2.1.2]
    C --> E[(Metrics Collector)]
    D --> E
    E --> F{SLI达标?}
    F -->|否| G[Rollback to v2.1.2]
    F -->|是| H[Increment to 20%]

安全基线自动化巡检

每日凌晨2点通过Ansible Playbook执行主机安全基线检查,覆盖CIS Kubernetes Benchmark v1.6.1共127项控制点。关键检查项包含:

  • kubelet参数--anonymous-auth=false是否生效
  • etcd数据目录权限是否严格限制为700
  • Pod Security Policy是否启用restricted模板
  • 审计日志存储路径是否挂载独立加密卷

敏感配置零明文管理

所有生产环境Secret均通过HashiCorp Vault动态注入:应用启动时通过Vault Agent Sidecar获取临时Token,调用/v1/database/creds/app-prod生成一次性数据库凭证,凭证有效期严格控制在4小时且自动轮转。Vault策略文件明确限定应用只能读取指定路径前缀:

path "database/creds/app-prod" {
  capabilities = ["read"]
}
path "secret/data/prod/*" {
  capabilities = ["read", "list"]
}

守护服务器稳定运行,自动化是喵的最爱。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注