Floci SSM 服务完全指南:Parameter Store 与 Run Command 的本地模拟实现
2026/9/20 15:22:35 网站建设 项目流程

【免费下载链接】floci

Light, fluffy, and always free - The AWS Local Emulator alternative

项目地址:https://gitcode.com/gh_mirrors/fl/floci
点击查看免费下载

本文以 Floci 开源项目(AWS Local Emulator alternative)的 SSM 服务文档 为核心,系统讲解其在本地完整模拟 AWS Systems Manager(SSM)的方式:从 JSON 1.1 协议接入、Parameter Store 全部受支持操作、公共 AMI 参数、Run Command 的两种执行路径(容器内直接执行与 SSM Agent 轮询),到存储与开关配置。读完本文,你将掌握如何在本地用 AWS CLI 与 SDK 无缝使用 SSM 参数管理与命令下发能力,并理解其与 EC2、IMDS 的联动边界。

协议接入:JSON 1.1 与统一端点

与 Floci 模拟的其他 AWS 服务一致,SSM 服务走 JSON 1.1 协议,所有请求都是POST到同一端点,通过X-Amz-Target头区分操作:

协议面X-Amz-Target 前缀说明
公开 API(Parameter Store / Run Command 等)AmazonSSM.*面向 AWS CLI 与 SDK 的标准操作
Agent 内部协议(ec2messages)AmazonSSMMessageDeliveryService.*amazon-ssm-agent轮询与回传结果使用
  • EndpointPOST http://localhost:4566/

从源码看,请求分发集中在 SsmJsonHandler.java 的handle(String action, JsonNode request, String region)方法——一个覆盖数十个操作的switch表达式;而 ec2messages 侧则由 Ec2MessagesJsonHandler.java 处理GetMessagesAcknowledgeMessageSendReplyFailMessageDeleteMessageGetEndpoint

Parameter Store:完整的参数生命周期

支持的 Actions

ActionDescription
PutParameterCreate or update a parameter
GetParameterGet a single parameter by name
GetParametersGet multiple parameters by name
GetParametersByPathGet all parameters under a path prefix
DeleteParameterDelete a parameter
DeleteParametersDelete multiple parameters
GetParameterHistoryList all versions of a parameter
DescribeParametersList parameters with optional filters
LabelParameterVersionAttach a label to a specific version
AddTagsToResourceTag a parameter
ListTagsForResourceList tags on a parameter
RemoveTagsFromResourceRemove tags from a parameter
DescribePatchBaselinesList AWS-owned predefined patch baselines (filter byOWNER,OPERATING_SYSTEM,NAME_PREFIX)
GetDefaultPatchBaselineGet the default patch baseline id for an operating system

版本化写入与保留命名空间(PutParameter)

putParameter的核心行为(SsmService.java)包括:

  • 每次写入返回递增的Version(已有参数version + 1,新参数从1开始),并为该参数追加一条历史记录;
  • 不加Overwrite时重复写入同名参数返回ParameterAlreadyExists(400),与 AWS 行为一致;
  • OverwriteTags不能同时使用,否则返回ValidationException
  • 参数 ARN 通过regionResolver.buildArn("ssm", region, "parameter" + name)生成,并记录LastModifiedDate
  • 保留命名空间校验rejectReservedName(SsmService.java)拒绝以awsssm开头的参数名(大小写不敏感、有无前导/均拒绝),保证账户参数永远无法覆盖 AWS 公共参数;校验基于首个路径段,因此ssm-auto-stack-Param-ABC这类 CloudFormation 自动生成的名字仍可正常写入。

版本历史通过addHistory维护,超过maxParameterHistory上限时丢弃最旧的记录(SsmService.java),历史条数上限由配置FLOCI_SERVICES_SSM_MAX_PARAMETER_HISTORY控制(默认 5)。

查询与批量删除(Get/Delete)

  • GetParameter:找不到返回ParameterNotFound;查找时会先查账户存储,再回落到公共参数(见下文公共 AMI 参数一节);
  • GetParameters:按名字批量读取,仅返回存在的参数,并把不存在的名字放入响应中的InvalidParameters数组(对应处理见 SsmJsonHandler.java);
  • GetParametersByPath:路径查询会把path规范化为以/结尾;Recursive=true匹配路径前缀下的全部参数,非递归时仅匹配直接子级(路径段内不含/),实现见underPath(SsmService.java);
  • DeleteParameter/DeleteParameters:删除参数同时清除其历史记录;批量删除响应同样携带DeletedParametersInvalidParameters两个数组。

过滤、分页与标签

  • DescribeParameters 过滤语义:多个过滤器之间按 AND 组合、单个过滤器内部按 OR 组合;支持的 Key 为NameTypeKeyIdPathTierDataType以及tag:<key>前缀;Path的 Option 支持Recursive/OneLevelName额外支持Contains,其余 Key 支持Equals/BeginsWith。非法 Key 返回InvalidFilterKey、非法 Option 返回InvalidFilterOption、非法值返回InvalidFilterValue,而不是静默放宽结果(校验逻辑见 SsmService.java)。由于 Floci 不存储 Tier 与客户 KMS Key,所有参数按StandardTier、SecureString 按默认alias/aws/ssmKey 报告;
  • 分页DescribeParameters支持MaxResults(1–50)与NextToken,超出范围返回ValidationException(SsmJsonHandler.java);同时兼容已废弃的Filters请求形态(仅接受Name/Type/KeyId);
  • 标签AddTagsToResource/ListTagsForResource/RemoveTagsFromResource支持以参数名或其 ARN 作为ResourceIdnormalizeResourceId会解析 ARN 中的parameter/资源段),标签在Overwrite更新时会被保留(SsmService.java);
  • 版本标签LabelParameterVersion把标签挂到指定版本的历史记录上,版本不存在返回ParameterVersionNotFound

Patch Baselines(预定义只读数据)

DescribePatchBaselinesGetDefaultPatchBaseline返回的是 AWS 拥有的预定义补丁基线静态数据(非客户状态,仅驻留内存),覆盖 WINDOWS、AMAZON_LINUX、AMAZON_LINUX_2/2022/2023、UBUNTU、RHEL、SUSE、CENTOS、ORACLE_LINUX、DEBIAN、MACOS、RASPBIAN、ROCKY_LINUX、ALMA_LINUX 等 15 个操作系统,基线 ID 由名称确定性生成(pb-<17位十六进制>),见buildPredefinedBaselines(SsmService.java)。OWNER=Self不返回任何结果(因为不存在客户自有基线)。

公共 AMI 参数:开箱即用的/aws/service/ami-amazon-linux-latest/

AWS 在每个账户下都发布只读的 AMI ID 查询参数(/aws/service/ami-amazon-linux-latest/),Terraform 模块无需任何配置即可读取。Floci 从自己的 EC2 镜像目录(Ec2ImageCatalog.java,findByPublicParameterName)应答文档化的 Amazon Linux 2 与 Amazon Linux 2023 参数名,因此GetParameterGetParametersGetParametersByPath都能解析出目录中的 AMI ID。

与 AWS 行为一致,这些公共参数:

  • 只读:不归属任何账户,因此不会出现在DescribeParametersGetParameterHistory中;
  • 只对目录中登记过的名字应答,/aws/service/前缀下的其他名字仍返回ParameterNotFound
  • 对祖先路径(如/aws)做递归GetParametersByPath时同样会列出。

实现位于publicParameter(SsmService.java),其 ARN 形如arn:aws:ssm:{region}::parameter{name}LastModifiedDate取镜像目录中的创建时间。

aws ssm get-parameter --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64

Parameter Types

所有 AWS 参数类型均被接受:StringStringListSecureString

注意SecureString参数在 Floci 中按原样存储,不做真实的 KMS 加密。类型会被保留并正确返回,但值在静态存储时并未加密。这一取舍可参考 SsmService.java 中参数模型仅保存明文值、未引入任何 KMS 交互的实现。

Run Command:两种执行路径

支持的 Actions

ActionDescription
UpdateInstanceInformationRegister or update an SSM agent record for an instance. Does not create an EC2 instance or register the container with IMDS (see Run Command Execution)
DescribeInstanceInformationList registered SSM managed instances
SendCommandCreate command invocations for target instances
GetCommandInvocationReturn a command invocation result
ListCommandsList command records
ListCommandInvocationsList command invocation records
CancelCommandCancel pending or in-progress command invocations

路径一:对 Floci EC2 实例的直接执行

SendCommand支持AWS-RunShellScript文档。当目标是Floci 通过 EC2RunInstances启动的容器(即容器由 Floci 管理、且正在运行)时,Floci 会:

  1. 创建命令(Command)与逐实例的调用记录(CommandInvocation),立即返回命令响应;
  2. 通过守护线程池(floci-ssm-direct-execution,见 SsmCommandService.java)异步在目标容器内执行脚本;
  3. 调用方通过GetCommandInvocation观察完成结果。

直接执行由 SsmDirectCommandExecutor.java 实现:

  • supports()判定两条条件:文档名为AWS-RunShellScript实例是运行中的 Floci EC2 容器(SsmDirectCommandExecutor.java);
  • 执行方式为 Dockerexecsh -c运行用户脚本,支持commands(多行合并)与workingDirectory参数,stdout/stderr 分别捕获(SsmDirectCommandExecutor.java);
  • 若容器内有timeout命令,脚本会被timeout --kill-after=1s包裹,从而在容器内限制超过TimeoutSeconds的命令(见timeoutWrappedScript);宿主侧等待时间为TimeoutSeconds + 2秒;
  • 退出码124/137/143视为超时,调用状态标记为TimedOutStatusDetailsExecution Timed Out;非零退出码标记为Failed

输出遵循 AWS 内联输出限制:stdout 保留前 24,000 字符、stderr 保留前 8,000 字符(常量MAX_STDOUT_CHARS/MAX_STDERR_CHARS,见 SsmCommandService.java)。stdoutstderr、响应码、开始时间、结束时间都会记录在调用记录上。

命令级状态由updateCommandStatus汇总:全部成功为Success;全部超时为TimedOut;全部失败为Failed;部分失败按 AWS 语义报告为Success(错误计数与超时计数仍单独记录)。由于Command对象在存储层是共享引用,状态写入使用synchronized(command)CancelCommand互斥,避免并发完成时状态与状态详情错位(SsmCommandService.java)。

路径二:SSM Agent 轮询(回退流程)

如果目标不是Floci EC2 容器,或文档不支持直接执行,Floci 回退到 SSM Agent 轮询流程:

  1. SendCommand把 ec2messages 负载入队(ConcurrentLinkedQueue,按instanceId分桶);
  2. 调用在 Agent 调用SendReply后才完成。

命令负载由buildCommandPayload构建并 Base64 编码,携带DocumentNameCommandIdParameters以及按 schemaVersion 2.2 生成的AWS-RunShellScript(或AWS-RunPowerShellScript)文档内容,供 Agent 执行(SsmCommandService.java)。

Managed instance 注册独立于 EC2 与 IMDS

UpdateInstanceInformation注册容器 SSM Agent 只创建 managed instance 记录。它不会创建 EC2 实例、不会在容器内安装 link-local169.254.169.254代理、也不会把容器注册到 EC2 IMDS 服务器。因此只注册过 SSM 的容器没有可用的 IMDS 端点、也没有实例配置文件凭据,针对它的SendCommand走的是 Agent 轮询流程而非直接执行。

要让一个容器既应答 IMDS 又能直接执行SendCommand,应先通过 EC2RunInstances启动它,再注册同一个容器的 SSM Agent。当 Agent 从未被 Floci EC2 实例托管的容器注册时,Floci 会记录一条警告日志(SsmCommandService.java)。

命令取消与实例信息

  • CancelCommand:把 Pending/InProgress 的调用标记为Cancelled,并移除该实例尚未轮询的消息;命令级状态同步置为Cancelled(SsmCommandService.java);
  • DescribeInstanceInformation:列出当前区域已注册的 managed instance(PingStatus=Online)。老版本 Agent 不发送InstanceId时,Floci 会生成mi-前缀的 ID;
  • SendCommand校验:缺少DocumentName返回InvalidDocument,无InstanceIds返回InvalidInstanceIdTimeoutSeconds默认 3600 且不得小于 30(返回ValidationException)。

ec2messages Agent 协议

ActionDescription
GetMessagesAgent polls for pending command messages
AcknowledgeMessageAgent acknowledges receipt of a command message
SendReplyAgent reports command output and status

协议流程(Ec2MessagesJsonHandler.java + SsmCommandService.java):

  • GetMessages:Agent 以Destination(instanceId)轮询待处理消息,消息被取出并登记到messageIndex用于回关联;VisibilityTimeoutInSeconds默认 30 秒;
  • AcknowledgeMessage:把对应调用从Pending推进到InProgress并记录执行开始时间;
  • SendReply:Agent 回传 Base64 编码的负载,Floci 解析runtimeStatus/pluginResults中的statusreturnCodestandardOutputstandardError,按 24,000/8,000 字符上限截断后写入调用记录,并触发命令级状态汇总;未知messageId会记录警告;
  • 另有FailMessage(Agent 报告处理失败)与DeleteMessage(丢弃消息)两个扩展操作;GetEndpoint返回config.effectiveBaseUrl()作为服务端点。

Configuration 配置项

VariableDefaultDescription
FLOCI_SERVICES_SSM_ENABLEDtrueEnable or disable the service
FLOCI_SERVICES_SSM_MAX_PARAMETER_HISTORY5Number of parameter versions retained per parameter
FLOCI_STORAGE_SERVICES_SSM_MODE(global default)Storage mode override for SSM (memory,persistent,hybrid,wal)
FLOCI_STORAGE_SERVICES_SSM_FLUSH_INTERVAL_MS5000Flush interval forhybrid/walstorage modes (milliseconds)

配置定义可追溯至 EmulatorConfig.java:

  • 服务开关与历史条数:SsmServiceConfig.enabled@WithDefault("true"))与SsmServiceConfig.maxParameterHistory@WithDefault("5")),位于 EmulatorConfig.java;
  • 存储覆盖:SsmStorageConfig.mode(可选,继承全局)与flushIntervalMs(默认 5000),位于 EmulatorConfig.java。

关于存储模式,参考 storage.md 中的四种后端:memory(最快、重启即失)、persistent(每次变更同步写盘)、hybrid(内存读 + 异步刷盘,适合日常本地开发)、wal(追加式预写日志 + 压缩,适合高写入)。注意:代码中@WithDefault的全局存储模式是hybrid,但发布的 Docker 镜像在application.yml中固定为memory,因此直接运行官方镜像时默认是memory,除非显式设置FLOCI_STORAGE_MODE。SSM 的持久化文件包括ssm-parameters.jsonssm-history.jsonssm-documents.jsonssm-instances.jsonssm-commands.jsonssm-invocations.json等(由SsmService/SsmCommandService通过StorageFactory创建)。

快速上手示例

以下示例假定 Floci 已在localhost:4566运行,AWS_ENDPOINT_URL指向该端点:

export AWS_ENDPOINT_URL=http://localhost:4566 # Store parameters aws ssm put-parameter --endpoint-url $AWS_ENDPOINT_URL \ --name /app/db/host --value "localhost" --type String aws ssm put-parameter --endpoint-url $AWS_ENDPOINT_URL \ --name /app/db/password --value "secret" --type SecureString # Retrieve aws ssm get-parameter --endpoint-url $AWS_ENDPOINT_URL \ --name /app/db/host aws ssm get-parameters-by-path --endpoint-url $AWS_ENDPOINT_URL \ --path /app/ --recursive # Delete aws ssm delete-parameter --endpoint-url $AWS_ENDPOINT_URL \ --name /app/db/host # Run a shell command on a Floci EC2 instance aws ssm send-command --endpoint-url $AWS_ENDPOINT_URL \ --instance-ids i-0123456789abcdef0 \ --document-name AWS-RunShellScript \ --parameters commands='["echo hello"]'

需要留意的是:直接执行要求--instance-ids指向由 FlociRunInstances启动的实例(其实例记录关联了运行中的 Docker 容器);对仅注册了 SSM Agent 的容器,命令会进入 Agent 轮询流程,需要容器内运行amazon-ssm-agent并轮询 ec2messages 才能完成。

验证与测试依据

  • 单元/集成测试集中在 src/test/java/io/github/hectorvent/floci/services/ssm/:SsmIntegrationTest覆盖参数增删改查、保留前缀拒绝(putParameterRejectsReservedPrefixes)、公共 AMI 参数解析(publicAmiParametersResolveWithoutSetup)、过滤与分页(describeParametersAppliesParameterFiltersdescribeParametersPagesWithMaxResultsAndNextToken)、文档共享与关联等;SsmSendCommandIntegrationTestSsmDirectCommandExecutorTestSsmCommandServiceDirectExecutionTest覆盖直接执行路径与超时/失败语义;
  • AWS CLI 兼容性测试见 compatibility-tests/sdk-test-awscli/test/ssm.bats,覆盖 put/get/get-parameters-by-path/标签/覆盖写/删除等场景;
  • SSM 与 IMDS 的联动边界说明见 ec2.md。

Floci 的 SSM 实现覆盖了 Parameter Store 全生命周期、公共 AMI 参数、Run Command 的双路径执行与 ec2messages Agent 协议,足以支撑本地开发、CI 测试以及 Terraform/CloudFormation 等 IaC 工具链对 SSM 的常规依赖;唯一需要开发者知悉的语义差异是SecureString不加密与命令执行必须经由 Floci EC2 容器(或真实 Agent 轮询)这两个本地模拟边界。

【免费下载链接】floci

Light, fluffy, and always free - The AWS Local Emulator alternative

项目地址:https://gitcode.com/gh_mirrors/fl/floci
点击查看免费下载
上一篇:彻底解决!Xtreme1数据集状态更新异常的5大核心方案与实现指南
下一篇:深入解析pymobiledevice3项目中XCUITestService无法启动WebDriverAgent的问题

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询