agentsclimarketplace

Lfx object store ops

Skill linuxfoundation/lfx-skills/skills/lfx-object-store-ops

Provisioning requirements for LFX object storage backends in deployed environments (prod, staging, shared dev): private S3 buckets, CloudFront with Origin Access Control, shared wildcard certificate, and IRSA write access, all in `lfx-v2-opentofu`. Written for the linuxfoundation GitHub org's ops audience — see the `-ops` skill convention in `/lfx-skills:lfx`. Fires on prompts like "provision a bucket", "object storage backend", "CloudFront for uploads", "S3 bucket opentofu", "IRSA for S3", "object store CDN", "bucket policy", "wildcard cert uploads". Requirements only; the implementing agent owns the HCL.From its SKILL.md

Install
npx -y skills add linuxfoundation/lfx-skills --skill lfx-object-store-ops

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 10 stars10 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

9.2 KB, as published. Nobody here has run it

<!-- Copyright The Linux Foundation and each contributor to LFX. --> <!-- SPDX-License-Identifier: MIT -->

LFX Object Store Ops

How the object storage backend is provisioned for deployed environments. This is a requirements stub, deliberately non-prescriptive: it captures the constraints the Ops team has agreed to, points at the existing conventions in lfx-v2-opentofu, and leaves the HCL to the implementing agent.

Audience: linuxfoundation GitHub org members. This skill is written for that ops audience and assumes org membership; it does not itself enforce it (see the -ops skill convention in /lfx-skills:lfx for how the router handles routing when membership is unconfirmed). Application-side design (endpoints, SDK usage, chart contract, local dev) is /lfx-skills:lfx-object-store-design.

Where

All resources live in lfx-v2-opentofu:

  • Environments are OpenTofu workspaces (dev, staging, prod), not directories. Resource names interpolate ${terraform.workspace} (see s3.tf for existing examples).
  • Workflow via the repo Makefile (make init/plan/apply); read the repo README.md before planning.

Pattern

Data-driven flat for_each, matching the postgres convention (postgres-database-definitions.yaml + postgres.tf). No new module — the Ops team prefers flat loops over YAML definitions; modules are reserved for cases that would otherwise require nested loops (see modules/eks-service-account-role/).

  • New object-store-definitions.yaml holding one entry per service bucket, including a boolean flag marking whether the bucket is public (CDN-fronted) — the design skill requires public and private files in separate buckets, so this is a per-bucket property, never mixed.
  • New object-storage.tf with one for_each per resource type. Bucket resources loop over every entry: aws_s3_bucket (+ versioning, SSE, lifecycle, public-access-block). CDN resources — aws_cloudfront_origin_access_control, aws_cloudfront_distribution, aws_s3_bucket_policy (OAC read policy), and the DNS alias records — loop over a filtered { for k, v in local.object_stores : k => v if v.public } so a distribution is only ever attached to explicitly public buckets. Attaching CloudFront/OAC to a service-API-only bucket would make its private objects anonymously retrievable. Still flat 1:1 loops, no nesting.

Requirements

Buckets

  • Private only. Public access block enabled; no public-read bucket policies. The existing lfx-one-project-logos-png-* buckets in s3.tf are a legacy anti-pattern — do not copy them.
  • Versioning and SSE enabled; names interpolate ${terraform.workspace}. Bucket versioning here is a data-protection feature (recovery from accidental delete/overwrite) — it is unrelated to the design skill's cache-busting query parameter (/lfx-skills:lfx-object-store-design, "Download flow"), which is an app-generated hint in public_url, not the S3 VersionId this setting produces. Do not conflate the two: enabling bucket versioning does not, by itself, invalidate CDN caches or change what the cache-busting parameter needs to look like.
  • Lifecycle rules are mandatory alongside versioning. With versioning on, DeleteObject only adds a delete marker and every overwrite retains the prior payload as a noncurrent version — without lifecycle expiration, storage grows unboundedly and user-"deleted" content is retained indefinitely (a data-retention problem, not just a cost one). Each bucket gets an aws_s3_bucket_lifecycle_configuration (1:1, same flat loop) that: expires noncurrent versions after 30 days, removes expired object delete markers, and aborts incomplete multipart uploads after 7 days.

CloudFront

  • Origin Access Control (OAC) with a SourceArn-conditioned bucket policy. Not the legacy OAI (aws_cloudfront_origin_access_identity) or forwarded_values patterns — the ITX cloudfront-distribution-with-s3 module is a structural reference only and must not be copied (deprecated OAI, forwarded_values, TLSv1).
  • Managed cache and origin-request policies that honor the per-object Cache-Control header. This header is object metadata set by the service at upload (PutObject's CacheControl field), not an origin or bucket configuration — the design skill's baseline is a short TTL, public, max-age=86400, since the cache-busting parameter is a hint rather than an immutable version. The design skill's cache-busting query parameter (see /lfx-skills:lfx-object-store-design) must be included in the cache key — a managed policy that strips query strings (such as the default CachingOptimized policy) will keep serving a stale object after the version parameter changes. Use a custom cache policy that forwards that parameter if the default managed policies exclude it. In that cache policy, set min_ttl = 0 — Minimum TTL is the only setting that overrides a shorter per-object max-age upward, and any nonzero value would defeat the service's short-TTL intent for persisted copies of the URL. default_ttl is different: it applies only when an object carries no Cache-Control metadata at all, never overriding a present header — keep it short (≤ 1 day) as a safety net for objects uploaded without the metadata.
  • One standardized default_cache_behavior (GET/HEAD); no per-path ordered_cache_behavior blocks — this keeps dynamic blocks out of the loop.

Certificates

  • One shared wildcard certificate; distribution aliases are shaped {bucket}.{vanity-domain} (vanity domain TBD, e.g. *.lfxuseruploads.com or *.downloads.lfx.community). This keeps ACM issuance and DNS validation — the one real nested-loop hazard — out of the per-bucket loop.
  • The certificate must be in us-east-1 (CloudFront requirement).

DNS

  • The alias and certificate alone do not publish the hostname: each {bucket}.{vanity-domain} name needs Route 53 alias A and AAAA records pointing at its CloudFront distribution, in the vanity domain's hosted zone. Enable IPv6 on the distribution (is_ipv6_enabled = true — it defaults to false) so the AAAA record is actually served. This is a per-public-bucket 1:1 resource — include it in the same filtered public-bucket loop as the distribution. Without it the CDN_URL_PREFIX handed off below will not resolve.

Write access (IRSA)

  • Service access via the existing IRSA mechanism: an entry in iam-service-account-definitions.yaml with an inline policy scoped to the service's bucket ARN(s), reconciled through modules/eks-service-account-role/. See lfx-v2-opentofu/docs/service-accounts.md.
  • The policy needs bucket-level s3:ListBucket (used by the service's HeadBucket readiness check and, if applicable, any internal listing — see /lfx-skills:lfx-object-store-design) plus object-level s3:GetObject, s3:PutObject, and s3:DeleteObject on {bucket-arn}/*. Do not grant s3:CreateBucket to a deployed role — the bucket is provisioned by this ops flow, not by the service at startup.
  • Bucket definition entries do not own IAM; keep the concerns separate.

Prohibitions

  • No public-read buckets or bucket ACLs.
  • No static credentials in deployed environments (IRSA only).
  • No Cloudflare R2 or other non-AWS deployments. "S3-compatible" in the design skill is app-side portability wording only.

Handoffs

After provisioning, hand these to lfx-v2-argocd environment values:

  • The IRSA role ARN. lfx-v2-argocd creates the ServiceAccount itself in its deployment manifests, carrying the eks.amazonaws.com/role-arn annotation; the service chart is configured with serviceAccount.create: false and serviceAccount.name to reference that externally created account (the chart does not render or annotate the SA in this mode).
  • The bucket name(s) (S3_BUCKET, or the purpose-prefixed variants from the design skill's multi-bucket namespacing) — one per bucket — plus the region (AWS_REGION) once: it is process-wide, and all of a service's buckets are provisioned in the environment's single region.
  • The CDN hostname (CDN_URL_PREFIX, e.g. https://{bucket}.{vanity-domain}) — one per CDN-fronted bucket.

Handoff boundary

The implementing agent in lfx-v2-opentofu owns the HCL, plan review, and apply workflow under that repo's local conventions. Application-side chart and code changes belong to the owning service repo per /lfx-skills:lfx-object-store-design.

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.