From f15b16f66d91cc53f636c799e35e42df65a7d9b2 Mon Sep 17 00:00:00 2001 From: Engin Diri Date: Thu, 14 Aug 2025 18:09:06 +0200 Subject: [PATCH 1/7] Add blog post: Deployment Guardrails with Policy as Code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This comprehensive blog post covers implementing deployment guardrails with Pulumi CrossGuard to create safe self-service infrastructure. It includes: - Real-world examples of policy implementation - Best practices for policy enforcement - Integration with CI/CD workflows - Compliance-ready policies for common frameworks Part of the IDP Best Practices series. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../index.md | 550 ++++++++++++++++++ .../meta.png | Bin 0 -> 24665 bytes 2 files changed, 550 insertions(+) create mode 100644 content/blog/deployment-guardrails-with-policy-as-code/index.md create mode 100644 content/blog/deployment-guardrails-with-policy-as-code/meta.png diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md new file mode 100644 index 000000000000..892cb4616861 --- /dev/null +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -0,0 +1,550 @@ +--- +title: "Deployment Guardrails with Policy as Code | IDP Workshop" +date: 2025-02-10T09:00:00Z +draft: false +meta_desc: "Implement deployment guardrails with Pulumi CrossGuard to create safe self-service infrastructure balancing developer autonomy and control." +meta_image: meta.png +authors: + - engin-diri +tags: + - idp + - platform-engineering + - policy-as-code + - crossguard + - compliance + - security + - self-service + - guardrails +--- + +**Building Safe Self-Service Infrastructure with Pulumi CrossGuard** + +Welcome to the third post in our **IDP Best Practices** series. In this workshop, we explore how to implement **policy as code** with [Pulumi CrossGuard](/docs/iac/packages-and-automation/crossguard) to create deployment guardrails that make self-service infrastructure both powerful and safe. + +Platform engineering is about enabling developer velocity while maintaining security and compliance. The challenge? How do you give teams the freedom to deploy infrastructure quickly without compromising on safety, security, or organizational standards? The answer lies in **automated guardrails** powered by policy as code. + + + +This post is part of our IDP Best Practices series: + +* [How to Build an Internal Developer Platform: Strategy, Best Practices, and Self-Service Infrastructure](/blog/idp-strategy-planning-self-service-infrastructure-that-balances-developer-autonomy-with-operational-control) +* [Build Golden Paths with Infrastructure Components and Templates](/blog/build-golden-paths-infrastructure-components-and-templates) +* **Deployment Guardrails with Policy as Code** (you are here) +* Day 2 Platform Operations: Automating Drift Detection and Remediation +* Extend Your IDP for AI Applications: GPUs, Models, and Cost Controls +* Next-Gen IDPs: How to Modernize Legacy Infrastructure with Pulumi + +{{% notes type="tip" %}} +**Want hands-on experience?** Access the [complete demo code](https://github.com/pulumi/workshops/tree/main/idp-component-policies) and [policy examples](https://github.com/pulumi/workshops/tree/main/idp-component-policies/demo-policies) from this workshop. Enroll in the free [IDP Builder Workshop Series](https://info.pulumi.com/idp/internal-developer-platform-workshops-course) for recordings and additional resources. +{{% /notes %}} + +## The Platform Engineering Challenge: Speed vs. Safety + +Picture this scenario from Statsig, a fast-growing feature flag platform processing 2 trillion events daily. They had one infrastructure engineer, Jason, who handled all infrastructure requests. When Jason went on parental leave, the entire engineering organization faced a bottleneck. Infrastructure requests piled up, deployments slowed, and the team realized they needed self-service infrastructure. + +But here's the challenge: **How do you enable self-service without sacrificing security, compliance, or operational stability?** + +This is where deployment guardrails with policy as code become essential. They transform the conversation from *"Talk to the infrastructure person"* to *"Ship with guardrails."* + +## Understanding Platform Engineering Layers + +Before diving into guardrails, let's understand where policy fits in your platform architecture: + +### Layer 1: Foundational Infrastructure + +* Security controls, shared networking, OIDC/IAM +* Managed by platform teams with strict access controls + +### Layer 2: Shared Infrastructure + +* VPCs, compute platforms, load balancers +* Standardized components with some customization + +### Layer 3: Workloads Layer + +* Deployable artifacts, pipelines, operability tools +* **This is where most self-service activity happens** +* **This is where guardrails are most critical** + +The workloads layer is where developers need the most freedom but also where the most risk exists. It's the perfect place for policy-driven guardrails. + +## What Are Deployment Guardrails? + +Deployment guardrails are **automated policies** that: + +1. **Prevent misconfigurations** before they reach production +2. **Enforce security standards** automatically +3. **Guide developers** toward best practices +4. **Enable safe self-service** by catching issues early + +Think of guardrails like type checking in programming languages. They don't restrict creativity—they catch errors early and guide developers toward correct patterns. + +## Introducing Pulumi CrossGuard: Policy as Code + +[Pulumi CrossGuard](/docs/iac/packages-and-automation/crossguard) is Pulumi's policy as code framework that enables you to: + +* Write policies in familiar programming languages ([Python](/docs/iac/packages-and-automation/crossguard/get-started#writing-policies-in-python), [TypeScript](/docs/iac/packages-and-automation/crossguard/get-started#writing-policies-in-typescript), Go) +* Enforce policies across all cloud resources and providers +* Run policies at different stages of the deployment lifecycle +* Integrate with CI/CD for automated enforcement + +### Key Policy Types + +**[Resource Policies](/docs/iac/packages-and-automation/crossguard/core-concepts#resource-validation)**: Validate individual resources + +```python +def restrict_dangerous_ports(args: ResourceValidationArgs, report_violation: ReportViolation): + if args.resource_type == "aws:lb/targetGroup:TargetGroup": + port = args.props.get("port") + dangerous_ports = ["22", "23", "3389"] + if str(port) in dangerous_ports: + report_violation("Dangerous port detected. Avoid using SSH, Telnet, or RDP ports.") +``` + +**[Stack Policies](/docs/iac/packages-and-automation/crossguard/core-concepts#stack-validation)**: Validate relationships across resources + +```python +def validate_microservice_encryption(args: StackValidationArgs, report_violation: ReportViolation): + microservice_components = [] + s3_buckets = [] + + for resource in args.resources: + if resource.resource_type == "custom:infrastructure:Microservice": + microservice_components.append(resource) + elif resource.resource_type == "aws:s3/bucket:Bucket": + s3_buckets.append(resource) + + if microservice_components and s3_buckets: + for bucket in s3_buckets: + encryption = bucket.props.get("serverSideEncryptionConfiguration") + if not encryption: + report_violation("S3 bucket must have encryption enabled when used with microservice components.") +``` + +## Building Practical Guardrails: Real-World Examples + +Let's walk through building guardrails for a microservice platform, starting with the component from our [previous workshop](/blog/build-golden-paths-infrastructure-components-and-templates). + +### Example 1: Port Security Policy + +**Problem**: Developers might accidentally expose services on dangerous ports like SSH (22) or RDP (3389). + +**Solution**: A policy that blocks dangerous port configurations. + +```python +import pulumi_policy as policy + +def restrict_dangerous_ports_validation(args, report_violation): + """Prevent services from running on dangerous ports.""" + if args.resource_type == "aws:lb/targetGroup:TargetGroup": + port = args.props.get("port") + dangerous_ports = ["22", "23", "3389", "5432", "3306"] + + if str(port) in dangerous_ports: + report_violation( + f"Port {port} is not allowed. This port is commonly used for " + f"administrative services and should not be exposed via load balancer." + ) + +restrict_dangerous_ports = policy.ResourceValidationPolicy( + name="restrict-dangerous-ports", + description="Prevent services from using dangerous ports", + validate=restrict_dangerous_ports_validation, + enforcement_level=policy.EnforcementLevel.MANDATORY +) +``` + +### Example 2: Resource Limits Policy + +**Problem**: Teams might request oversized resources, leading to cost overruns. + +**Solution**: A policy that enforces reasonable resource limits with advisory warnings. + +```python +def limit_memory_validation(args, report_violation): + """Limit memory allocation for microservices.""" + if args.resource_type == "custom:infrastructure:Microservice": + # Extract memory from component tags or properties + memory_str = args.props.get("memory", "512Mi") + + # Parse memory value (assuming format like "2Gi", "1024Mi") + if memory_str.endswith("Gi"): + memory_gb = float(memory_str[:-2]) + if memory_gb > 1: + report_violation( + f"Memory allocation of {memory_str} exceeds recommended limit of 1Gi " + f"for microservices. Consider optimizing your application or " + f"contact the platform team for exceptions." + ) + +limit_memory = policy.ResourceValidationPolicy( + name="limit-microservice-memory", + description="Enforce reasonable memory limits for microservices", + validate=limit_memory_validation, + enforcement_level=policy.EnforcementLevel.ADVISORY +) +``` + +### Example 3: Cross-Resource Security Policy + +**Problem**: When microservices use S3 buckets, encryption should be mandatory. + +**Solution**: A stack policy that validates encryption across related resources. + +```python +def microservice_s3_encryption_validation(args, report_violation): + """Ensure S3 buckets used with microservices have encryption enabled.""" + microservice_resources = [] + s3_buckets = [] + + # Collect relevant resources + for resource in args.resources: + if resource.resource_type == "custom:infrastructure:Microservice": + microservice_resources.append(resource) + elif resource.resource_type == "aws:s3/bucket:Bucket": + s3_buckets.append(resource) + + # If we have both microservices and S3 buckets, check encryption + if microservice_resources and s3_buckets: + for bucket in s3_buckets: + sse_config = bucket.props.get("serverSideEncryptionConfiguration") + if not sse_config: + report_violation( + f"S3 bucket '{bucket.name}' must have server-side encryption " + f"enabled when used with microservice components." + ) + +microservice_s3_encryption = policy.StackValidationPolicy( + name="microservice-s3-encryption", + description="Ensure S3 buckets used with microservices are encrypted", + validate=microservice_s3_encryption_validation, + enforcement_level=policy.EnforcementLevel.MANDATORY +) +``` + +## Policy Enforcement Models + +Pulumi CrossGuard supports multiple [enforcement models](/docs/iac/packages-and-automation/crossguard/core-concepts#enforcement-levels) to fit different workflows: + +### 1. Preventative Model + +Policies run **before** resources are created: + +* **Advantage**: Fast feedback, prevents bad deployments +* **Use case**: Block dangerous configurations before they reach the cloud +* **Example**: Validating port configurations, resource limits + +```bash +# Policies run automatically during preview and deployment +pulumi preview # Policies evaluated here +pulumi up # Policies block deployment if violations found +``` + +### 2. Detective Model + +Policies run **after** resources are created: + +* **Advantage**: Can validate actual cloud state, including outputs +* **Use case**: Compliance scanning, drift detection +* **Example**: Checking that auto-generated ARNs follow naming conventions + +### 3. CI/CD Integration + +Policies run as part of your deployment pipeline: + +* **Advantage**: Consistent enforcement across teams +* **Use case**: Pull request validation, deployment gates +* **Example**: [GitHub Actions](/docs/iac/packages-and-automation/continuous-delivery/github-actions) that block merges if policies fail + +```yaml +# GitHub Actions example +- name: Run Policy Validation + run: | + pulumi preview --policy-pack ./policies + if [ $? -ne 0 ]; then + echo "Policy violations found. Deployment blocked." + exit 1 + fi +``` + +## Policy Remediation: Beyond Detection + +Modern policy frameworks don't just detect violations—they can **[automatically fix](/docs/iac/packages-and-automation/crossguard/core-concepts#remediation-policies)** them: + +```python +def auto_tag_resources(args, report_violation): + """Automatically add required tags to resources.""" + if args.resource_type == "aws:s3/bucket:Bucket": + tags = args.props.get("tags", {}) + + if "Department" not in tags: + # Instead of just reporting, fix the issue + if not hasattr(args, 'tags'): + args.props["tags"] = {} + args.props["tags"]["Department"] = "Engineering" + return args.props # Return modified properties + + return None # No changes needed + +auto_tag_policy = policy.ResourceValidationPolicy( + name="auto-tag-resources", + description="Automatically add required tags", + validate=auto_tag_resources, + enforcement_level=policy.EnforcementLevel.REMEDIATE +) +``` + +## Server-Side Policy Enforcement + +For enterprise deployments, Pulumi provides [server-side policy enforcement](/docs/iac/packages-and-automation/crossguard/get-started#enforcing-a-policy-pack): + +1. **Publish policies** to your Pulumi organization: + + ```bash + pulumi policy publish ./my-policies + ``` + +2. **[Create policy groups](/docs/pulumi-cloud/organization/organization-policies)** that combine policies with enforcement levels: + * Target specific stacks or environments + * Set different enforcement levels (advisory, mandatory) + * Configure exceptions for special cases + +3. **Automatic enforcement**: Policies run automatically without CLI flags + +This ensures policies can't be bypassed and provides consistent governance across your organization. + +## Compliance-Ready Policies + +Pulumi provides hundreds of [pre-built policies](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies) for common compliance frameworks: + +```typescript +import { PolicyManager } from "@pulumi/policy"; +import { policyManager } from "@pulumi/compliance-ready-policies/policy-manager"; + +new PolicyPack("aws-compliance-ready-policies-typescript", { + policies: [ + ...policyManager.selectPolicies({ + vendors: ["aws"], + services: ["ec2", "s3"], + severities: ["medium", "high", "critical"], + topics: ["encryption"], + frameworks: ["pcidss"], + }, "mandatory"), + ], +}); +``` + +This automatically includes policies for: + +* **[PCI DSS](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies#frameworks)**: Payment card industry standards +* **[SOC 2](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies#frameworks)**: Security and compliance controls +* **[ISO 27001](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies#frameworks)**: Information security management +* **[CIS Benchmarks](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies#frameworks)**: Security configuration standards + +## Best Practices for Policy Implementation + +### 1. Start Small and Iterate + +* Begin with 2-3 critical policies +* Use [advisory enforcement](/docs/iac/packages-and-automation/crossguard/core-concepts#enforcement-levels) initially +* Graduate to mandatory enforcement after team feedback + +### 2. Provide Clear Error Messages + +```python +def good_error_message(args, report_violation): + if violation_detected: + report_violation( + "S3 bucket encryption is required for compliance. " + "Add serverSideEncryptionConfiguration to fix this. " + "See: https://docs.company.com/s3-encryption" + ) +``` + +### 3. Use Progressive Enforcement + +* **[Advisory](/docs/iac/packages-and-automation/crossguard/core-concepts#advisory)**: Warn but allow deployment +* **[Mandatory](/docs/iac/packages-and-automation/crossguard/core-concepts#mandatory)**: Block deployment +* **[Remediate](/docs/iac/packages-and-automation/crossguard/core-concepts#remediation-policies)**: Automatically fix issues + +### 4. Test Your Policies + +```python +# Test policies with unit tests +def test_dangerous_port_policy(): + # Mock resource with port 22 + args = create_mock_args("aws:lb/targetGroup:TargetGroup", {"port": 22}) + violations = run_policy(restrict_dangerous_ports, args) + assert len(violations) == 1 + assert "dangerous port" in violations[0].message.lower() +``` + +### 5. Document Escape Hatches + +Not every policy will fit 100% of use cases. Provide clear processes for: + +* Requesting policy exceptions +* Temporary exemptions for emergencies +* Appeals process for policy changes + +## Real-World Success: Statsig's Transformation + +After implementing guardrails, Statsig achieved remarkable results: + +> *"We had a single infra owner. Parental leave forced us to build self-service, and that's when everything clicked. Developers open a PR, Pulumi previews the change right in the PR, and CI blocks risky changes. That's how you move fast safely. The magic was turning 'talk to the infra person' into 'ship with guardrails.'"* +> +> — Tyrone Wong, Infrastructure Engineer at Statsig + +**Key outcomes:** + +* **Faster deployments**: From 1.5 weeks to minutes +* **Reduced operational burden**: No more infrastructure ticket queues +* **Maintained security**: Automated policy enforcement +* **Improved developer satisfaction**: Self-service without friction + +## Building Your Policy Strategy + +### Phase 1: Assessment (Week 1-2) + +* Audit current infrastructure patterns +* Identify common misconfigurations +* Document security requirements +* Survey developer pain points + +### Phase 2: Foundation (Week 3-4) + +* Implement 3-5 core policies +* Set up [CI/CD integration](/docs/iac/packages-and-automation/continuous-delivery) +* Start with advisory enforcement +* Create documentation and runbooks + +### Phase 3: Expansion (Month 2) + +* Add [compliance-specific policies](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies) +* Implement [server-side enforcement](/docs/pulumi-cloud/organization/organization-policies) +* Create policy exemption processes +* Measure and track policy effectiveness + +### Phase 4: Optimization (Ongoing) + +* Monitor policy violations and trends +* Refine policies based on feedback +* Add [automated remediation](/docs/iac/packages-and-automation/crossguard/core-concepts#remediation-policies) +* Expand to new services and teams + +## Measuring Policy Success + +Track these metrics to validate your policy strategy: + +### Security Metrics + +* **Policy violation rate**: Percentage of deployments flagged +* **Time to remediation**: How quickly violations are fixed +* **Security incident reduction**: Fewer misconfigurations in production + +### Developer Experience Metrics + +* **Deployment velocity**: Time from code to production +* **Developer satisfaction**: Survey scores about platform experience +* **Support ticket volume**: Reduction in infrastructure requests + +### Operational Metrics + +* **Policy coverage**: Percentage of resources under policy control +* **Exemption rate**: How often policies are bypassed +* **Remediation automation**: Percentage of violations auto-fixed + +## Common Pitfalls and How to Avoid Them + +### Pitfall 1: Over-Engineering Policies + +**Problem**: Creating overly complex policies that are hard to understand +**Solution**: Start simple, use clear naming, provide examples + +### Pitfall 2: Policy Theater + +**Problem**: Implementing policies that don't address real risks +**Solution**: Base policies on actual incidents and security requirements + +### Pitfall 3: Poor Developer Experience + +**Problem**: Cryptic error messages and no clear remediation steps +**Solution**: Invest in clear documentation and helpful error messages + +### Pitfall 4: Inadequate Testing + +**Problem**: Policies that break legitimate use cases +**Solution**: Test policies thoroughly with real scenarios before enforcement + +## The Future of Policy as Code + +As infrastructure becomes more complex, policy as code will evolve to include: + +### AI-Enhanced Policies + +* **Smart detection**: ML-powered anomaly detection +* **Contextual recommendations**: Policies that adapt based on usage patterns +* **Predictive enforcement**: Catching issues before they become violations + +### Cross-Cloud Governance + +* **Universal policies**: Rules that work across [AWS](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies-aws), [Azure](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies-azure), [GCP](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies-gcp) +* **Federated enforcement**: Consistent policies across multiple cloud accounts +* **Compliance automation**: Automated evidence collection for audits + +### Developer-Centric Policies + +* **IDE integration**: Real-time policy feedback during development +* **Self-service exemptions**: Automated approval workflows +* **Learning policies**: Systems that improve based on developer feedback + +## Getting Started: Your Action Plan + +Ready to implement deployment guardrails? Here's your roadmap: + +1. **Assess Current State** (Week 1) + * Document existing infrastructure patterns + * Identify security and compliance requirements + * Survey developer pain points + +2. **Create Foundation Policies** (Week 2-3) + * Implement 3-5 core security policies + * Set up local policy testing + * Create clear documentation + +3. **Integrate with CI/CD** (Week 4) + * Add policy validation to pull requests + * Configure deployment blocking for violations + * Set up monitoring and alerting + +4. **Expand and Optimize** (Month 2+) + * Add compliance-specific policies + * Implement server-side enforcement + * Create exemption and appeals processes + +5. **Scale Across Organization** (Month 3+) + * Extend policies to all teams + * Add automated remediation + * Establish policy governance processes + +## Conclusion: Enabling Safe Self-Service at Scale + +Deployment guardrails with policy as code transform the platform engineering equation. Instead of choosing between speed and safety, you can have both. By automating policy enforcement, you enable developers to move fast while automatically maintaining security, compliance, and operational standards. + +The key insight from successful platform teams like Statsig is that **guardrails enable freedom**. When developers know their deployments will be caught if they violate policies, they feel confident making infrastructure changes. When platform teams know policies automatically enforce standards, they can focus on strategic initiatives instead of manual reviews. + +Policy as code isn't about restriction—it's about **intelligent automation** that makes the right thing the easy thing. + +### Ready to Build Your Guardrails? + +* **Explore the demo code**: Check out our [complete policy examples](https://github.com/pulumi/workshops/tree/main/idp-component-policies/demo-policies) +* **Learn more about CrossGuard**: Read the [official documentation](/docs/iac/packages-and-automation/crossguard) +* **Try AWSGuard**: Get started with [pre-built AWS policies](/docs/iac/packages-and-automation/crossguard/awsguard) +* **Explore compliance policies**: Browse our [compliance-ready policy catalog](/docs/iac/packages-and-automation/crossguard/compliance-ready-policies) +* **Get hands-on experience**: Join our [IDP Builder Workshop Series](https://info.pulumi.com/idp/internal-developer-platform-workshops-course) +* **Watch the webinar**: Learn about [policy as code for cloud compliance](https://www.pulumi.com/resources/cloud-compliance-policy-as-code/) +* **Connect with the community**: Join the [Pulumi Slack](https://slack.pulumi.com) #platform-engineering channel + +*Next in our series: Day 2 Platform Operations - Automating Drift Detection and Remediation. Learn how to maintain infrastructure compliance after deployment and automatically remediate configuration drift.* + +{{< get-started >}} diff --git a/content/blog/deployment-guardrails-with-policy-as-code/meta.png b/content/blog/deployment-guardrails-with-policy-as-code/meta.png new file mode 100644 index 0000000000000000000000000000000000000000..44a346913c3498ce31b90f943b1e2830cd0ca816 GIT binary patch literal 24665 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 Date: Thu, 14 Aug 2025 18:11:31 +0200 Subject: [PATCH 2/7] Fix ordered list numbering in Server-Side Policy Enforcement section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Indent code block within list item to maintain list continuity - Fixes markdown linter errors for ordered list item prefixes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../blog/deployment-guardrails-with-policy-as-code/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md index 892cb4616861..725c0fcdebe4 100644 --- a/content/blog/deployment-guardrails-with-policy-as-code/index.md +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -1,11 +1,11 @@ --- -title: "Deployment Guardrails with Policy as Code | IDP Workshop" +title: "Deployment Guardrails with Policy as Code" date: 2025-02-10T09:00:00Z draft: false meta_desc: "Implement deployment guardrails with Pulumi CrossGuard to create safe self-service infrastructure balancing developer autonomy and control." meta_image: meta.png authors: - - engin-diri + - adam-gordon-bell tags: - idp - platform-engineering From a64fb078795129970868f5ee695b5c8a262d0653 Mon Sep 17 00:00:00 2001 From: Engin Diri Date: Thu, 14 Aug 2025 18:17:03 +0200 Subject: [PATCH 3/7] Update blog post date to today and fix author MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Set publication date to 2025-08-14 - Restore correct author (engin-diri) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../blog/deployment-guardrails-with-policy-as-code/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md index 725c0fcdebe4..14a1f69167d5 100644 --- a/content/blog/deployment-guardrails-with-policy-as-code/index.md +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -1,11 +1,11 @@ --- title: "Deployment Guardrails with Policy as Code" -date: 2025-02-10T09:00:00Z +date: 2025-08-14T09:00:00Z draft: false meta_desc: "Implement deployment guardrails with Pulumi CrossGuard to create safe self-service infrastructure balancing developer autonomy and control." meta_image: meta.png authors: - - adam-gordon-bell + - engin-diri tags: - idp - platform-engineering From f1f07e31dc4560c2060eb43cd7be0f3fe2001cd4 Mon Sep 17 00:00:00 2001 From: Engin Diri Date: Thu, 14 Aug 2025 18:18:03 +0200 Subject: [PATCH 4/7] Fix author to adam-gordon-bell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Correct author attribution as requested 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- content/blog/deployment-guardrails-with-policy-as-code/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md index 14a1f69167d5..a800f7a8dec7 100644 --- a/content/blog/deployment-guardrails-with-policy-as-code/index.md +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -5,7 +5,7 @@ draft: false meta_desc: "Implement deployment guardrails with Pulumi CrossGuard to create safe self-service infrastructure balancing developer autonomy and control." meta_image: meta.png authors: - - engin-diri + - adam-gordon-bell tags: - idp - platform-engineering From a365126b5b19ab16e511601118df13a1c2f0a914 Mon Sep 17 00:00:00 2001 From: Engin Diri Date: Thu, 14 Aug 2025 18:36:39 +0200 Subject: [PATCH 5/7] Add series field to blog post header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add series: idp-best-practices to YAML front matter - Links post to the IDP Best Practices series 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- content/blog/deployment-guardrails-with-policy-as-code/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md index a800f7a8dec7..033af59a25ef 100644 --- a/content/blog/deployment-guardrails-with-policy-as-code/index.md +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -6,6 +6,7 @@ meta_desc: "Implement deployment guardrails with Pulumi CrossGuard to create saf meta_image: meta.png authors: - adam-gordon-bell +series: idp-best-practices tags: - idp - platform-engineering From 5521b34b01960849a166fbe729a78216cfc9836f Mon Sep 17 00:00:00 2001 From: Engin Diri Date: Thu, 14 Aug 2025 18:40:19 +0200 Subject: [PATCH 6/7] Remove redundant bolded line from blog post introduction --- content/blog/deployment-guardrails-with-policy-as-code/index.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md index 033af59a25ef..56867cdb5eec 100644 --- a/content/blog/deployment-guardrails-with-policy-as-code/index.md +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -18,8 +18,6 @@ tags: - guardrails --- -**Building Safe Self-Service Infrastructure with Pulumi CrossGuard** - Welcome to the third post in our **IDP Best Practices** series. In this workshop, we explore how to implement **policy as code** with [Pulumi CrossGuard](/docs/iac/packages-and-automation/crossguard) to create deployment guardrails that make self-service infrastructure both powerful and safe. Platform engineering is about enabling developer velocity while maintaining security and compliance. The challenge? How do you give teams the freedom to deploy infrastructure quickly without compromising on safety, security, or organizational standards? The answer lies in **automated guardrails** powered by policy as code. From 159efe8db12fb2b5bac629c0658eed03672aa84f Mon Sep 17 00:00:00 2001 From: Sara <100384099+SaraDPH@users.noreply.github.com> Date: Thu, 14 Aug 2025 12:58:05 -0500 Subject: [PATCH 7/7] Update content/blog/deployment-guardrails-with-policy-as-code/index.md --- .../blog/deployment-guardrails-with-policy-as-code/index.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/blog/deployment-guardrails-with-policy-as-code/index.md b/content/blog/deployment-guardrails-with-policy-as-code/index.md index 56867cdb5eec..5ab125612596 100644 --- a/content/blog/deployment-guardrails-with-policy-as-code/index.md +++ b/content/blog/deployment-guardrails-with-policy-as-code/index.md @@ -1,5 +1,6 @@ --- -title: "Deployment Guardrails with Policy as Code" +title: "How to Implement Robust Security Guardrails Using Policy as Code" +allow_long_title: true date: 2025-08-14T09:00:00Z draft: false meta_desc: "Implement deployment guardrails with Pulumi CrossGuard to create safe self-service infrastructure balancing developer autonomy and control."