Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions code/go/pkg/validator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ func Test_ValidateFromPath(t *testing.T) {
"field group: Does not match pattern '^[a-z0-9_]+$'",
},
},
"good_iac_blueprints": {},
"good_iac_blueprints_input": {},
"good_blueprint": {},
"bad_iac_blueprints_missing_required": {
"manifest.yml",
[]string{
`field iac_blueprints.0: format is required`,
`field iac_blueprints.0: patches is required`,
},
},
"bad_iac_blueprints_invalid_format": {
"manifest.yml",
[]string{
`field iac_blueprints.0.format: iac_blueprints.0.format must be one of the following: "cloudformation", "arm", "terraform", "deployment-manager", "helm", "kustomize", "ansible", "bicep"`,
},
},
"bad_duration_vars": {
"manifest.yml",
[]string{
Expand Down
29 changes: 29 additions & 0 deletions spec/blueprint/blueprints/spec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
##
## Describes the layout of the blueprints/ payload folder.
##
## Files are laid out to mirror the blueprint `id` (<provider>/<trust-model>/<scope>)
## with the `format` and file extension appended:
##
## blueprints/<provider>/<trust-model>/<scope>.<format>.<ext>
##
## e.g. blueprints/aws/federated-identity/account.cloudformation.json
##
spec:
additionalContents: false
contents:
- description: Provider directory (e.g. aws, azure, gcp)
type: folder
pattern: '^[a-z0-9][a-z0-9-]*$'
required: true
additionalContents: false
contents:
- description: Trust-model directory (e.g. federated-identity, workload-identity, service-principal)
type: folder
pattern: '^[a-z0-9][a-z0-9-]*$'
required: true
additionalContents: false
contents:
- description: A canonical IaC blueprint file, named <scope>.<format>.<ext>
type: file
pattern: '^[a-z0-9][a-z0-9_-]*\.[a-z0-9-]+\.[a-z0-9]+$'
required: true
54 changes: 54 additions & 0 deletions spec/blueprint/manifest.spec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
##
## Describes the specification for the blueprint package's main manifest.yml file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need a separate blueprint package type? Isn't it enough to allow input and integration packages to define blueprints?

I would expect that the permissions and other definitions in a blueprint would need to be tied to specific integration versions, so it seems preferable to bundle them into the existing package types, rather than have a separate package the likely introduces the need for version compatibility rules.

It seems much nicer to be able to test the AWS package as a complete unit for example.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cmacknz How do we deal if there are like multiple, like 20 odd AWS integrations that need same blueprint , If we limit the blueprint inside one integration then probably we would have to duplicate it for other similar integrations?

The purpose was to have one place of truth for all these blueprints that could be used by multiple packages. Reusing input / integration types might causes problems in Fleet UI if we do not have any Kibana/ES assets probably?

If the naming needs to be generic , like to reuse the package type for any general purpose template / prompt / text / asset storage mechanism then we can use more generic / base package naming convention.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needing to reuse these is valid, but creating a separate package type creates a compatibility check problem as I mentioned so if reuse is the only reason for a separate package we maybe need another way to reuse configuration in packages.

It should be possible for us to create a way to reuse configuration across integrations without creating a new releasable user artifact. We should not be publishing packages whose main purpose is just config reuse in other packages.

@teresaromero teresaromero Aug 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was thinking on this re-use and had the links idea since the last meeting, so i went ahead and checked this out.

The proposal: use elastic-package .link files to share the canonical blueprint asset across integration packages.

The .link mechanism already exists — a .link file is a plain text pointer ( ) that elastic-package resolves transparently at build time. The built package zip contains the real file content, not the pointer. elastic-package links update/check keeps checksums in sync and fails the build on drift.

I ran a POC on the elastic/integrations repo to verify this approach: elastic/integrations#20721

  • Created account.cloudformation.json.link files inside the iac/ directories of aws, cloud_asset_inventory, and cloud_security_posture, all pointing to a single shared source.
  • elastic-package links update computed checksums for all three.
  • elastic-package build on cloud_asset_inventory produced a zip with iac/account.cloudformation.json — real content, correct filename — confirming that LinksFS resolves iac/*.link at build time, not just elasticsearch/ingest_pipeline/ and fields/.
  • Cross-package links (pointing outside a package's own tree) work fine.

Where to store the shared source:

  1. shared/blueprints/aws/federated-identity/account.cloudformation.json at repo root — neutral, no ownership coupling.
  2. Inside one authoritative integration (e.g., aws) — makes ownership explicit but creates a dependency.

What this avoids: no new type: blueprint in the spec, no EPR changes, no new elastic-package support for a new package type. The canonical template is just a file — shared via a mechanism the toolchain already understands.

@bhapas The iac folder will contain "blueprint" + patches; would the service that patches permissions be able to grab from this folder all the files?

@mrodm will this be a challenge for backporting a package? having a linked file source on root repo? would it be better to have it on a package and link the other from there?

from this we could also update elastic-package so it can simulate the permissions patching and have this asset tested during development; as we do now with policies with fleet (thinking out loud)

@mrodm mrodm Aug 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrodm will this be a challenge for backporting a package? having a linked file source on root repo? would it be better to have it on a package and link the other from there?

@teresaromero Yes, I think linking files between different packages is going to be problematic when doing backports.

Currently, we suggest that new backport branches should be created just with the required package and remove the others. If the linked file is going to be located in another package, when creating the backport branch it is likely that the linked file does not exist. In that case one option is that the owners should copy the source of the linked file from the commit where the backport branch was created.

In order to support that, scripts that copy the contents of the backport branches should also to take into account the source of the linked files to ensure that any other necessary package is kept. And this is not considered currently in this process.

If the linked file is in the root of the repository could also cause some issues. For instance, when a change in that blueprint folder in the root of the repository is introduced, it is not going to be easy to know to which packages affect and which branches should be backported. If possible, I would try to avoid this (thinking in backports).

EDIT:

And for instance, changes in the packages containing the source of the links will not be suggested as part of the backport process automation.

It is difficult to ensure that the backport process automation would take care of all these scenarios.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created issue to ensure that the source packages of the linked files are copied too elastic/integrations#20726

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created issue to ensure that the source packages of the linked files are copied too elastic/integrations#20726

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cmacknz Agree that we should not be publishing packages that just package a reusable config for other [ specific set of ] packages.

@teresaromero

The .link mechanism already exists — a .link file is a plain text pointer ( ) that elastic-package resolves transparently at build time. The built package zip contains the real file content, not the pointer. elastic-package links update/check keeps checksums in sync and fails the build on drift.

This sounds good. Except that I have a few questions around this.

  • This approach means that every built package will have a copy of blueprint in it , right?
  • Let's say , we want to develop a new development version of the blueprint [ Like .../aws/fi/account-v2-preview ] , I guess this should be possible?
  • If we want multiple versions of blueprints to co-exist I guess we can just create additional folders for the versions [ aws/federated-identity/account-v1 ] [ aws/federated-identity/account-v2 ] where major bump is for non-backwards compatible changes to the template.
  • For simplicity , I guess each package has to have one base template reference at all levels - policy_template , data_stream , integration , input levels.
  • When there is a base template update , I guess all the downstream packages need a new version release [ Probably rightly so , rather than silently updating a template ].

@bhapas The iac folder will contain "blueprint" + patches; would the service that patches permissions be able to grab from this folder all the files?

Yes , it should be possible if we can read the specific resources from the gcloud bucket.

@mrodm will this be a challenge for backporting a package? having a linked file source on root repo? would it be better to have it on a package and link the other from there?

For backport branches , specific package versions can have specific base template instead of a link. That way we work with the specific template manually in that backport branch.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link concept solves this, the backporting issues can be solved through the tooling updates Mario suggested hopefully. One day might just have to commit to maintaining backport branches of the entire integrations repository if this is troublesome.

I don't think the link concept prevents anything related to breaking changes or multiple versions of a blueprint at once. You can change what the links point to, have current and next versions of a blueprint etc. they would just all coexist on the main branch. Potentially you might want a version

Maybe we need to iterate on the ergonomics of this a bit but conceptually this direction makes sense to me.

##
spec:
# Everything under here follows JSON schema (https://json-schema.org/), written as YAML for readability
type: object
additionalProperties: false
properties:
format_version:
description: The version of the package specification format used by this package.
$ref: "../integration/manifest.spec.yml#/definitions/version"
name:
description: The name of the package.
type: string
pattern: '^[a-z0-9_]+$'
examples:
- elastic_iac_blueprints
title:
$ref: "../integration/manifest.spec.yml#/definitions/title"
description:
$ref: "../integration/manifest.spec.yml#/definitions/description"
version:
description: The version of the package.
$ref: "../integration/manifest.spec.yml#/definitions/version"
source:
$ref: "../integration/manifest.spec.yml#/definitions/source"
type:
description: The type of package.
type: string
enum:
- blueprint
examples:
- blueprint
conditions:
description: Conditions under which this package can be installed.
type: object
additionalProperties: false
properties:
elastic:
$ref: "../integration/manifest.spec.yml#/definitions/conditions/properties/elastic"
kibana:
$ref: "../integration/manifest.spec.yml#/definitions/conditions/properties/kibana"
owner:
$ref: "../integration/manifest.spec.yml#/definitions/owner"
deprecated:
$ref: "../integration/manifest.spec.yml#/definitions/deprecated"
required:
- format_version
- name
- title
- description
- version
- type
- owner
53 changes: 53 additions & 0 deletions spec/blueprint/spec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
##
## Entrypoint of "blueprint packages" specification.
##
## A blueprint package is a versioned bundle of canonical Infrastructure-as-Code (IaC)
## base templates ("blueprints"). Unlike other package types it is not installed into
## Kibana, Elasticsearch, or the Elastic Agent — it is fetched by the cloud-iac-provisioner
## renderer, which applies each enabled integration's RFC 6902 `iac_blueprints` patches on
## top of the canonical blueprint to produce one deployable artifact.
##
## Describes the folders and files that make up a package.
##
spec:
additionalContents: false
totalContentsLimit: 65535
totalSizeLimit: 250MB
sizeLimit: 150MB
configurationSizeLimit: 5MB
relativePathSizeLimit: 3MB
contents:
- description: The main package manifest file
type: file
contentMediaType: "application/x-yaml"
sizeLimit: 5MB
name: "manifest.yml"
required: true
$ref: "./manifest.spec.yml"
- description: The package's CHANGELOG file
type: file
contentMediaType: "application/x-yaml"
name: "changelog.yml"
required: true
$ref: "../integration/changelog.spec.yml"
- description: The package's license file
type: file
contentMediaType: "text/plain"
name: "LICENSE.txt"
required: false
- description: Folder containing documentation for the package
type: folder
name: docs
required: true
$ref: "../integration/docs/spec.yml"
- description: Folder containing the canonical IaC base blueprints served to the renderer
type: folder
name: blueprints
required: true
$ref: "./blueprints/spec.yml"
- description: Configuration file to process the results returned from the package validation. This file is just for package validation and it should be ignored when installing or using the package.
type: file
contentMediaType: "application/x-yaml"
name: "validation.yml"
required: false
$ref: "../integration/validation.spec.yml"
9 changes: 9 additions & 0 deletions spec/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
- description: Add support for semantic_text field definition.
type: enhancement
link: https://github.com/elastic/package-spec/pull/807
- description: Extend provider_permissions.permissions items with resource scoping (resources array) and conditional narrowing (conditions object) fields.
type: enhancement
link: https://github.com/elastic/security-team/issues/18258
- description: Add iac_blueprints field at package, policy_template, input, and data_stream levels for IaC composition contributions via RFC 6902 patch files.
type: enhancement
link: https://github.com/elastic/security-team/issues/18260
- description: Add `blueprint` package type for hosting canonical IaC base blueprints served to the cloud-iac-provisioner renderer.
type: enhancement
link: https://github.com/elastic/security-team/issues/18260
- version: 3.6.6
changes:
- description: Add support for mode-aware constructors and validation APIs.
Expand Down
10 changes: 10 additions & 0 deletions spec/input/manifest.spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ spec:
$ref: "../integration/manifest.spec.yml#/definitions/sections"
provider_permissions:
$ref: "../integration/manifest.spec.yml#/definitions/provider_permissions"
iac_blueprints:
$ref: "../integration/manifest.spec.yml#/definitions/iac_blueprints"
input:
type: string
examples:
Expand Down Expand Up @@ -152,6 +154,8 @@ spec:
$ref: "../integration/manifest.spec.yml#/definitions/sections"
provider_permissions:
$ref: "../integration/manifest.spec.yml#/definitions/provider_permissions"
iac_blueprints:
$ref: "../integration/manifest.spec.yml#/definitions/iac_blueprints"
owner:
$ref: "../integration/manifest.spec.yml#/definitions/owner"
agent:
Expand All @@ -178,6 +182,12 @@ spec:

# JSON patches for newer versions should be placed on top
versions:
- before: 3.7.0
patch:
- op: remove
path: "/properties/policy_templates/items/properties/iac_blueprints"
- op: remove
path: "/properties/iac_blueprints"
- before: 3.6.0
patch:
- op: remove
Expand Down
4 changes: 4 additions & 0 deletions spec/integration/data_stream/manifest.spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -766,12 +766,16 @@ spec:
$ref: "../../integration/manifest.spec.yml#/definitions/deprecated"
provider_permissions:
$ref: "../../integration/manifest.spec.yml#/definitions/provider_permissions"
iac_blueprints:
$ref: "../../integration/manifest.spec.yml#/definitions/iac_blueprints"
required:
- title
# JSON patches for newer versions should be placed on top
versions:
- before: 3.7.0
patch:
- op: remove
path: "/properties/iac_blueprints"
# Variable-level scope migration.
- op: remove
path: /definitions/vars/items/properties/migrate_from
Expand Down
80 changes: 80 additions & 0 deletions spec/integration/manifest.spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,66 @@ spec:
description:
description: Human-readable description of why this permission is needed.
type: string
resources:
description: >
Provider-native resource targets this permission applies to (ARNs, Azure resource paths,
GCP resource selectors, K8s apiGroup/resource, SQL object names, …).
When omitted the permission applies account-wide.
type: array
items:
type: string
examples:
- - "arn:aws:s3:::my-log-bucket/*"
- - "arn:aws:s3:::*"
- - "/subscriptions/*/resourceGroups/*/providers/Microsoft.Storage/storageAccounts/*"
conditions:
description: >
Provider-native conditions that narrow when this permission applies
(AWS Condition block, Azure conditions, GCP IAM Conditions in CEL, …).
type: object
iac_blueprints:
description: >
IaC composition contributions this integration unit makes to a shared canonical blueprint.
Pointers to RFC 6902 patch files the cloud-iac-provisioner renderer applies on top of a
canonical blueprint to produce one deployable artifact covering all enabled integrations.
May be declared at package, policy_template, input, and data_stream levels;
contributions across all applicable levels are merged into a single artifact.
type: array
items:
type: object
additionalProperties: false
required:
- id
- format
- patches
properties:
id:
description: >
Blueprint identifier in the form <provider>/<trust-model>/<scope>,
e.g. aws/federated-identity/account.
type: string
examples:
- aws/federated-identity/account
- azure/service-principal/subscription
- gcp/workload-identity/project
format:
description: IaC format this patch targets.
type: string
enum:
- cloudformation
- arm
- terraform
- deployment-manager
- helm
- kustomize
- ansible
- bicep
patches:
description: Relative path inside the package to the RFC 6902 JSON Patch file.
type: string
title:
description: Optional human-readable label for this IaC contribution.
type: string
properties:
format_version:
description: The version of the package specification format used by this package.
Expand Down Expand Up @@ -859,6 +919,8 @@ spec:
$ref: "#/definitions/conditions"
provider_permissions:
$ref: "#/definitions/provider_permissions"
iac_blueprints:
$ref: "#/definitions/iac_blueprints"
# requires a conditional JSON schema to update the value depending
# on the policy_templates length
policy_templates_behavior:
Expand Down Expand Up @@ -1005,6 +1067,8 @@ spec:
- credential_type: [cloud_connectors]
provider_permissions:
$ref: "#/definitions/provider_permissions"
iac_blueprints:
$ref: "#/definitions/iac_blueprints"
required:
- title
- description
Expand Down Expand Up @@ -1033,6 +1097,8 @@ spec:
$ref: "#/definitions/deprecated"
provider_permissions:
$ref: "#/definitions/provider_permissions"
iac_blueprints:
$ref: "#/definitions/iac_blueprints"
required:
- name
- title
Expand Down Expand Up @@ -1101,6 +1167,20 @@ spec:

# JSON patches for newer versions should be placed on top
versions:
- before: 3.7.0
patch:
- op: remove
path: "/definitions/iac_blueprints"
- op: remove
path: "/properties/iac_blueprints"
- op: remove
path: "/properties/policy_templates/items/properties/iac_blueprints"
- op: remove
path: "/properties/policy_templates/items/properties/inputs/items/properties/iac_blueprints"
- op: remove
path: "/definitions/provider_permissions/items/properties/permissions/items/properties/resources"
- op: remove
path: "/definitions/provider_permissions/items/properties/permissions/items/properties/conditions"
- before: 3.6.0
patch:
# Input qualifier (named inputs).
Expand Down
Loading