Persistent vs Non-Persistent Resources
Persistent vs Non-Persistent Resources
Understanding the difference between persistent and non-persistent resources is fundamental to designing secure, maintainable CI/CD pipelines. This appendix explains what these terms mean, why the distinction matters, and how it affects your deployment strategy.
What Are Persistent Resources?
Persistent resources are long-lived infrastructure components that:
- Store data or state that must survive across deployments
- Serve shared or foundational purposes
- Are expensive or time-consuming to recreate
- Often have dependencies on other resources
- May require manual intervention to modify
Common examples in cloud environments:
| Category | Examples | Why Persistent? |
|---|---|---|
| Identity | Managed identities, service principals, user accounts | Must exist before any workload can authenticate |
| Secrets | Key Vaults, secret stores | Centralized, shared access across multiple workloads |
| Networking | VNETs, subnets, firewalls, load balancers | Shared infrastructure, complex dependencies |
| Databases | SQL servers, Cosmos DB, storage accounts | Store data, require migration for schema changes |
| Security | Policy definitions, role assignments, audit configurations | Governance, compliance, cross-workload access control |
| Monitoring | Log Analytics workspaces, Application Insights | Aggregate data across services |
Key characteristics of persistent resources:
- Created early in the environment setup
- Modified infrequently (not in every CI/CD run)
- Often managed by platform/security teams, not application teams
- Require careful change management
- May have dependencies that make recreation difficult
What Are Non-Persistent Resources?
Non-persistent resources are ephemeral infrastructure components that:
- Are created and destroyed frequently
- Contain no critical state that must be preserved
- Can be recreated quickly and cheaply
- Are often replaced rather than modified
- Serve temporary or application-specific purposes
Common examples in cloud environments:
| Category | Examples | Why Non-Persistent? |
|---|---|---|
| Compute | App Service instances, container instances, VMs (dev/test) | Can be recreated, state is externalized |
| Deployment | Application code deployments, configuration files | Always rebuilt from source |
| Testing | Test fixtures, temporary databases | Created for specific test runs |
| CI/CD | Pipeline run artifacts, build containers | Temporary by nature |
| Development | Dev/test environment copies | Destroyed after use or periodically |
Key characteristics of non-persistent resources:
- Created and destroyed frequently
- State stored externally (in databases, object storage, etc.)
- Can be replaced rather than modified
- Often managed by application teams
- Suitable for fully automated CI/CD pipelines
Why Separation Matters in CI/CD
The Problem: Mixed Responsibilities
When persistent and non-persistent resources are managed together in the same pipeline/state file, several problems arise:
Problems with mixed management:
- Different deployment frequencies: Application code changes daily; identity permissions change rarely
- Different risk profiles: App deployment failures are expected; identity changes require careful review
- Different ownership: Application team deploys app; platform team manages identities
- Different failure modes: App failures are recoverable; identity changes can cause cascading failures
- State file complexity: Managing both makes state management harder and more error-prone
The Solution: Separated Pipelines and States
Benefits of separation:
| Aspect | Mixed State | Separated States |
|---|---|---|
| Deployment frequency | All resources deployed together | App: daily; Platform: rarely |
| Failure impact | One pipeline failure blocks everything | App failures don't affect platform |
| Access control | App identity needs broad permissions | App identity needs minimal scope |
| Team ownership | Blurred responsibilities | Clear team boundaries |
| State size | Grows large and unwieldy | Smaller, focused states |
| Review process | Mixed criticality changes | Platform changes get extra review |
How Separation Affects CI/CD Design
Pipeline Frequency and Triggers
Non-persistent resource pipeline (application):
# Example: Application deployment pipeline
trigger:
branches:
include:
- main
- develop
tags:
include:
- v* # Release buildsPersistent resource pipeline (platform):
# Example: Platform infrastructure pipeline
trigger: none # Manual or scheduled only
# Or schedule for periodic review
trigger:
batch: true
intervals:
- 1 weekPermission Scopes
Service connection permissions:
- Deploy to specific App Service
- Write to specific Key Vault secrets
- Read from specific managed identity
- Never: Modify RBAC, create identities, change network config
Platform service connection permissions:
- Create and manage managed identities
- Assign RBAC roles
- Configure network resources
- Manage Key Vault access policies
State File Isolation
Application state (dev-app.tfstate):
resource "azurerm_linux_web_app" "app" { ... }
resource "azurerm_linux_web_app_slot" "staging" { ... }
resource "azurerm_key_vault_secret" "app_config" { ... }Platform state (platform.tfstate):
resource "azurerm_managed_identity" "app_identity" { ... }
resource "azurerm_role_assignment" "app_kv_access" { ... }
resource "azurerm_key_vault" "app_kv" { ... }Practical Implementation Patterns
Pattern 1: Two-Tier Terraform
Tier 1: Platform/Infra (persistent)
- Managed by platform or SecOps team
- Deployed to "platform" or "core" resource group
- State file:
platform.tfstate - Contains: Identities, network, security, shared services
Tier 2: Application (non-persistent)
- Managed by application team
- Deployed to "apps" or "application" resource group
- State file:
app-name.tfstate - Contains: App services, deployments, app-specific config
Pattern 2: Output-Based Dependencies
Platform outputs (platform.tfstate):
output "app_managed_identity_object_id" {
value = azurerm_managed_identity.app_identity.object_id
}
output "app_key_vault_uri" {
value = azurerm_key_vault.app_kv.vault_uri
}Application uses Terraform remote state to read those outputs:
# Application state file (dev-app.tfstate)
terraform {
backend "azurerm" {
# ... app state config
}
}
# Data source to read from platform state
data "azurerm_remote_state" "platform" {
name = "platform"
azure_rm {
subscription_id = data.azurerm_client_config.current.subscription_id
resource_group_name = "rg-platform"
storage_account_name = "stplatform"
container_name = "state"
key = "platform.tfstate"
}
}
locals {
# Read outputs directly from platform state
app_identity_object_id = data.azurerm_remote_state.platform.outputs["app_managed_identity_object_id"]
app_kv_uri = data.azurerm_remote_state.platform.outputs["app_key_vault_uri"]
}
resource "azurerm_linux_web_app" "app" {
# Use the platform-provided identity
identity {
identity_ids = [data.azurerm_remote_state.platform.outputs["app_managed_identity_object_id"]]
}
# Reference the Key Vault for secrets
app_settings = {
AZURE_KEYVAULT_URI = data.azurerm_remote_state.platform.outputs["app_key_vault_uri"]
}
}Anti-Patterns to Avoid
Anti-Pattern 1: All-in-One State
Problem: Single state file contains everything from identities to deployments.
# BAD: Everything in one file
resource "azurerm_managed_identity" "app" { ... } # Persistent
resource "azurerm_role_assignment" "..." { ... } # Persistent
resource "azurerm_linux_web_app" "app" { ... } # Non-persistent
resource "azurerm_linux_web_app_slot" "staging" { ... } # Non-persistentWhy it's bad:
- Pipeline must have broad permissions
- Deployment frequency mismatch
- Harder to audit and understand
Anti-Pattern 2: App Team Managing Everything
Problem: Application team has Contributor on resource group containing both app and platform resources.
Why it's bad:
- App team can accidentally modify platform resources
- No separation of concerns
- Audit trail is mixed
Anti-Pattern 3: Frequent Platform Changes
Problem: Platform resources changed in every deployment like application code.
Why it's bad:
- Platform resources should be stable
- Frequent changes indicate wrong classification
- Makes testing and verification harder
Verification Questions
Before moving to production, verify your separation strategy:
- Ownership: Can you clearly identify who manages each resource type?
- Frequency: Does deployment frequency match resource characteristics?
- Permissions: Does the deployment identity have minimal required scope?
- Failure isolation: Can app failures not affect platform resources?
- State clarity: Is each state file focused and manageable?
Summary
Persistent resources are shared, long-lived infrastructure that changes rarely:
- Identity, secrets, network, security, databases
- Managed by platform/SecOps teams
- Deployed infrequently with extra review
Non-persistent resources are application-specific, frequently changing components:
- Compute, deployments, app configuration
- Managed by application teams
- Deployed frequently with automation
Separation benefits:
- Clearer ownership and accountability
- Differentiated deployment frequencies
- Reduced blast radius for failures
- Smaller, more manageable state files
- Better security (least privilege)
Key principle: Deploy once, deploy often applies differently:
- Platform: deploy carefully, rarely
- Application: deploy frequently, automatically
Key Takeaways
Summary
This appendix explained the fundamental distinction between persistent and non-persistent resources and why separating their management is critical for secure, maintainable infrastructure:
Persistent resources are shared, long-lived infrastructure components that:
- Store state or data that must survive across deployments
- Are expensive or time-consuming to recreate
- Change infrequently and require careful review
- Are typically managed by platform/SecOps teams
Non-persistent resources are application-specific components that:
- Can be recreated quickly and cheaply
- Have their state externalized (databases, object storage)
- Change frequently as application code evolves
- Are managed by application teams
Why This Matters
The separation enables:
- Different deployment frequencies: Applications deploy daily; platform changes weekly or monthly
- Reduced blast radius: App failures don't impact platform resources
- Clearer ownership: Teams know exactly what they manage
- Minimal permissions: App identities only need access to what they use, not full platform control
- Manageable state files: Focused states are easier to audit and troubleshoot
When to Use Each Type
| Resource Type | When to Classify as Persistent | When to Classify as Non-Persistent |
|---|---|---|
| Compute | Production databases, shared services | Dev/test VMs, ephemeral containers |
| Identity | Managed identities, service principals | CI/CD run identities |
| Storage | Shared storage accounts, blobs | Temporary staging areas |
| Network | VNETs, subnets, firewalls | Temporary NAT gateways |
| Secrets | Key Vault, central secrets store | In-app configuration |
| Deployment | Infrastructure as code | Application code artifacts |
Decision framework:
- If it stores data or shared state → Persistent
- If it's expensive or slow to recreate → Persistent
- If multiple applications depend on it → Persistent
- If it can be destroyed and recreated without impact → Non-persistent
How This Applies Throughout the Course
This persistent/non-persistent distinction appears in every day of the course:
Day 1: Identity Foundations
- Persistent: Managed identities, service principals, role assignments
- Non-persistent: Application identities within each environment
Day 2: Network Security
- Persistent: VNETs, subnets, NSGs, private endpoints
- Non-persistent: Application-specific network configurations
Day 3: Secure Development
- Persistent: Key Vault, security policies, RBAC
- Non-persistent: Application deployments, artifacts, test environments
Day 4: Monitoring (upcoming)
- Persistent: Log Analytics workspaces, Application Insights instances
- Non-persistent: Environment-specific metrics, temporary alert rules
Pattern Recognition
Every lab will follow this pattern:
- Platform resources (persistent) are created first
- Application resources (non-persistent) depend on platform outputs
- Application pipelines read platform outputs rather than modifying platform resources
Practical Guidance
For Platform Teams
- Own the foundation: Create identities, networks, security policies
- Publish outputs: Expose resource references (IDs, URIs) as outputs
- Protect the platform: Require review for all changes
- Document interfaces: Clearly define what each resource provides
For Application Teams
- Consume, don't modify: Read platform outputs, never change platform resources
- Externalize state: Store application state in databases, not in compute
- Design for replacement: Treat your compute resources as disposable
- Use proper permissions: Request minimal access to platform resources
For DevOps Engineers
- Split state files: Never mix persistent and non-persistent in one state
- Split pipelines: Platform pipeline vs. application pipeline
- Use remote state: Application reads platform via Terraform remote state
- Automate responsibly: Platform changes need gates; application can be fully automated
Remember
"Deploy carefully, rarely" applies to platform. "Deploy frequently, automatically" applies to applications.
- Terraform State Management - Best practices for state organization
- Azure Landing Zones - Enterprise-scale reference architecture
- The Twelve-Factor App - Principle 10: Dev/prod parity
- Azure Well-Architected Framework - Reliability and Security pillars