Manage Cloud Visibility and Governance with Infrastructure as Code

Posted on

Do you know what cloud resources are running in your environment right now? Many organizations struggle to maintain visibility across their cloud estate, especially for resources created outside of infrastructure as code. Without complete visibility, you can’t enforce compliance, optimize costs, or identify security risks.

Today, we’re excited to announce new resources in the Pulumi Service Provider that solve this problem by enabling you to discover all cloud resources and enforce governance policies programmatically using infrastructure as code.

With these new resources, you can:

  • Discover all cloud resources across AWS, Azure, GCP, Kubernetes, or OCI environments, including resources not managed by Pulumi
  • Import discovered resources into Pulumi management using Visual Import to bring unmanaged infrastructure under IaC control
  • Enforce compliance at scale by organizing resources into Policy Groups and applying policy packs
  • Automate governance workflows by managing everything through code, enabling GitOps and CI/CD integration

What’s New

The Pulumi Service Provider now includes three new resources for managing cloud visibility and governance:

ResourceDescription
InsightsAccountConfigures cloud provider scanning for resource discovery
PolicyGroupOrganizes stacks or cloud accounts for policy enforcement
getPolicyPacks / getPolicyPackData sources for querying available policy packs

Let’s explore each of these in detail.

Insights Accounts: Discover Your Cloud Resources

An InsightsAccount connects Pulumi Cloud to your cloud provider, enabling automated scanning and discovery of all resources in your environment. This gives you complete visibility into your cloud estate, including resources that aren’t managed by Pulumi.

Key Features

  • Multi-cloud support: Scan AWS, Azure, GCP, Kubernetes, and OCI environments
  • Scheduled scanning: Configure daily automated scans or trigger them on-demand
  • Resource tagging: Organize your accounts with custom tags

Example: Creating an AWS Insights Account

name: insights-example
runtime: yaml
resources:
  # ESC environment with AWS credentials
  aws-credentials:
    type: pulumiservice:Environment
    properties:
      organization: my-org
      project: insights
      name: aws-credentials
      yaml:
        fn::stringAsset: |
          values:
            aws:
              login:
                fn::open::aws-login:
                  oidc:
                    roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
                    sessionName: pulumi-insights
            environmentVariables:
              AWS_REGION: us-west-2

  # Insights account for AWS scanning
  aws-insights:
    type: pulumiservice:InsightsAccount
    properties:
      organizationName: my-org
      accountName: production-aws
      provider: aws
      environment: insights/aws-credentials
      scanSchedule: daily
      providerConfig:
        regions:
          - us-west-2
          - us-east-1
      tags:
        environment: production
        team: platform
import * as pulumi from "@pulumi/pulumi";
import * as pulumiservice from "@pulumi/pulumiservice";

// ESC environment with AWS credentials
const awsCredentials = new pulumiservice.Environment("aws-credentials", {
    organization: "my-org",
    project: "insights",
    name: "aws-credentials",
    yaml: new pulumi.asset.StringAsset(`
values:
  aws:
    login:
      fn::open::aws-login:
        oidc:
          roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
          sessionName: pulumi-insights
  environmentVariables:
    AWS_REGION: us-west-2
`),
});

// Insights account for AWS scanning
const awsInsights = new pulumiservice.InsightsAccount("aws-insights", {
    organizationName: "my-org",
    accountName: "production-aws",
    provider: "aws",
    environment: pulumi.interpolate`${awsCredentials.project}/${awsCredentials.name}`,
    scanSchedule: "daily",
    providerConfig: {
        regions: ["us-west-2", "us-east-1"],
    },
    tags: {
        environment: "production",
        team: "platform",
    },
});
import pulumi
import pulumi_pulumiservice as pulumiservice

# ESC environment with AWS credentials
aws_credentials = pulumiservice.Environment("aws-credentials",
    organization="my-org",
    project="insights",
    name="aws-credentials",
    yaml=pulumi.StringAsset("""
values:
  aws:
    login:
      fn::open::aws-login:
        oidc:
          roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
          sessionName: pulumi-insights
  environmentVariables:
    AWS_REGION: us-west-2
"""))

# Insights account for AWS scanning
aws_insights = pulumiservice.InsightsAccount("aws-insights",
    organization_name="my-org",
    account_name="production-aws",
    provider="aws",
    environment=pulumi.Output.concat(aws_credentials.project, "/", aws_credentials.name),
    scan_schedule="daily",
    provider_config={
        "regions": ["us-west-2", "us-east-1"],
    },
    tags={
        "environment": "production",
        "team": "platform",
    })
package main

import (
	"github.com/pulumi/pulumi-pulumiservice/sdk/go/pulumiservice"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		// ESC environment with AWS credentials
		awsCredentials, err := pulumiservice.NewEnvironment(ctx, "aws-credentials", &pulumiservice.EnvironmentArgs{
			Organization: pulumi.String("my-org"),
			Project:      pulumi.String("insights"),
			Name:         pulumi.String("aws-credentials"),
			Yaml: pulumi.NewStringAsset(`
values:
  aws:
    login:
      fn::open::aws-login:
        oidc:
          roleArn: arn:aws:iam::123456789012:role/PulumiInsightsRole
          sessionName: pulumi-insights
  environmentVariables:
    AWS_REGION: us-west-2
`),
		})
		if err != nil {
			return err
		}

		// Insights account for AWS scanning
		_, err = pulumiservice.NewInsightsAccount(ctx, "aws-insights", &pulumiservice.InsightsAccountArgs{
			OrganizationName: pulumi.String("my-org"),
			AccountName:      pulumi.String("production-aws"),
			Provider:         pulumi.String("aws"),
			Environment: pulumi.Sprintf("%s/%s", awsCredentials.Project, awsCredentials.Name),
			ScanSchedule:     pulumi.String("daily"),
			ProviderConfig: pulumi.Map{
				"regions": pulumi.ToStringArray([]string{"us-west-2", "us-east-1"}),
			},
			Tags: pulumi.StringMap{
				"environment": pulumi.String("production"),
				"team":        pulumi.String("platform"),
			},
		})
		if err != nil {
			return err
		}

		return nil
	})
}

Policy Groups: Enforce Compliance at Scale

A PolicyGroup lets you organize resources and apply policy packs for compliance enforcement. Policy Groups support two entity types: Stacks and Accounts.

You can configure policy groups in two modes:

  • Audit mode: Reports policy violations without blocking operations. This supports both Stacks and Accounts.
  • Preventative mode: Blocks operations that violate policies. This mode is only available for Stacks.

Example: Stack-Based Policy Group

Apply compliance policies to your Pulumi stacks:

name: policy-group-example
runtime: yaml
resources:
  production-policies:
    type: pulumiservice:PolicyGroup
    properties:
      name: production-compliance
      organizationName: my-org
      entityType: stacks
      mode: preventative
      stacks:
        - name: production
          routingProject: my-app
        - name: staging
          routingProject: my-app
      policyPacks:
        - name: cis-aws
          displayName: CIS AWS Foundations Benchmark
          version: 1
          versionTag: "1.5.0"
import * as pulumiservice from "@pulumi/pulumiservice";

const productionPolicies = new pulumiservice.PolicyGroup("production-policies", {
    name: "production-compliance",
    organizationName: "my-org",
    entityType: "stacks",
    mode: "preventative",
    stacks: [
        { name: "production", routingProject: "my-app" },
        { name: "staging", routingProject: "my-app" },
    ],
    policyPacks: [
        {
            name: "cis-aws",
            displayName: "CIS AWS Foundations Benchmark",
            version: 1,
            versionTag: "1.5.0",
        },
    ],
});

Example: Account-Based Policy Group

Apply compliance policies to your cloud accounts for resource governance:

name: insights-policy-group
runtime: yaml
resources:
  # Insights account
  aws-insights:
    type: pulumiservice:InsightsAccount
    properties:
      organizationName: my-org
      accountName: production-aws
      provider: aws
      environment: insights/aws-credentials

  # Policy group targeting the Insights account
  cloud-compliance:
    type: pulumiservice:PolicyGroup
    properties:
      name: cloud-resource-compliance
      organizationName: my-org
      entityType: accounts
      mode: audit
      accounts:
        - ${aws-insights.accountName}
      policyPacks:
        - name: aws-security-best-practices
          displayName: AWS Security Best Practices
          version: 2
import * as pulumiservice from "@pulumi/pulumiservice";

// Insights account
const awsInsights = new pulumiservice.InsightsAccount("aws-insights", {
    organizationName: "my-org",
    accountName: "production-aws",
    provider: "aws",
    environment: "insights/aws-credentials",
});

// Policy group targeting the Insights account
const cloudCompliance = new pulumiservice.PolicyGroup("cloud-compliance", {
    name: "cloud-resource-compliance",
    organizationName: "my-org",
    entityType: "accounts",
    mode: "audit",
    accounts: [awsInsights.accountName],
    policyPacks: [
        {
            name: "aws-security-best-practices",
            displayName: "AWS Security Best Practices",
            version: 2,
        },
    ],
});

Querying Policy Packs

Use the getPolicyPacks and getPolicyPack data sources to discover available policy packs in your organization:

name: policy-packs-query
runtime: yaml
variables:
  # List all available policy packs
  availablePacks:
    fn::invoke:
      function: pulumiservice:getPolicyPacks
      arguments:
        organizationName: my-org
      return: policyPacks

outputs:
  policyPacks: ${availablePacks}
import * as pulumiservice from "@pulumi/pulumiservice";

// List all available policy packs
const availablePacks = pulumiservice.getPolicyPacksOutput({
    organizationName: "my-org",
});

export const policyPacks = availablePacks.policyPacks;

Getting Started

To start using these new resources:

Update the Pulumi Service Provider to the latest version:

npm install @pulumi/pulumiservice@latest
pip install --upgrade pulumi-pulumiservice
go get github.com/pulumi/pulumi-pulumiservice/sdk/go/pulumiservice@latest
dotnet add package Pulumi.PulumiService

No package installation needed for YAML - just use the resources directly.

Learn More

We’re excited to see how you use these new capabilities to improve visibility and governance across your cloud infrastructure. As always, we welcome your feedback in our Community Slack or on GitHub.