Sections

Palo Alto StrataBest practices

Strata Cloud Manager Automation

Automation options, capabilities, and practical code for managing configuration in Palo Alto Networks Strata Cloud Manager (SCM).

Stack
Strata Cloud Manager, scm-go, Terraform
Practice area
Security Automation & AI
Domain
Strata Cloud Manager configuration automation
Scope
scm-go, the Terraform provider, Python SDKs, CRUD patterns, and JWT caching for Strata Cloud Manager.
Role
Cybersecurity Engineer & Architect
Updated

Why automate SCM

Manual configuration in the SCM UI does not scale when managing:

  • Multiple environments (dev, staging, production)
  • Mixed deployments (on-prem NGFWs, VM-Series in Azure/AWS/GCP, Cloud NGFW)
  • Frequent or repetitive changes
  • Requirements for consistency, auditability, and speed

Automation treats configuration as code: versioned, reviewable, and repeatable.

Automation options

OptionBest forNotes
Optionscm-goBest forCustom Go scripts, internal tools, CI jobsNotesPalo Alto Networks’ Go SDK. Auto-generated and community supported. Full control over API calls. [1], [2]
OptionTerraform provider (scm)Best forDeclarative infrastructure-as-codeNotesBuilt on scm-go. Provides state, plans, and team workflows. [4], [5]
OptionPython: scm-pythonBest forPython environments, lightweight scriptsNotesPalo Alto Networks’ auto-generated Python SDK. Currently a beta pre-release that its README says is not ready for production use. [6]
OptionPython: pan-scm-sdkBest forExisting scripts that already use itNotesCommunity SDK with Pydantic models. Its repository now asks users to use the official SDK from Palo Alto instead. [7]
OptionAnsible modulesBest forExisting Ansible estatesNotesAvailable; check module coverage for the resources you need before choosing it.
OptionDirect REST APIBest forCases not covered by higher-level toolsNotesMaximum flexibility; more boilerplate required. [8]

scm-go is the foundational Go client. Higher-level tools such as the Terraform provider use it underneath. [5]

Scope of automation

The SDK covers configuration managed through Strata Cloud Manager, including: [9]

  • Objects: addresses, address groups, services, tags, applications, EDLs, HIP objects/profiles, schedules
  • Security: security rules, decryption rules/profiles, anti-spyware, vulnerability protection, URL filtering, file blocking
  • Network: interfaces, zones, NAT rules, PBF, IKE/IPsec, BGP, OSPF, SD-WAN, zone protection
  • Setup: folders, snippets, devices, variables, labels
  • Deployment, identity, mobile agent, and ZTNA Connector resources

Because the SDK manages configuration held in SCM, it applies to firewalls and deployments that SCM manages, such as NGFWs and VM-Series firewalls onboarded to SCM and Cloud NGFW resources that use SCM for policy management. Confirm SCM support for each firewall type and deployment before automating it.

Authentication and client setup

Credentials are obtained from a service account in SCM (client ID, client secret, TSG scope).

Configuration resolution order in scm-go: explicit struct fields → environment variables (only when CheckEnvironment is true) → scm-config.json → built-in defaults, such as the host api.strata.paloaltonetworks.com. [3]

Example scm-config.json (placeholder values):

json
{
  "client_id": "<your-client-id>",
  "client_secret": "<your-client-secret>",
  "host": "api.strata.paloaltonetworks.com",
  "protocol": "https",
  "scope": "tsg_id:<your-tsg-id>",
  "logging": "quiet",
  "skip_verify_certificate": false
}

Reusable authentication and client initialization:

go
package main

import (
	"context"

	scm "github.com/paloaltonetworks/scm-go"
	"github.com/paloaltonetworks/scm-go/generated/objects"
)

// configPath points to your scm-config.json, for example /path/to/scm-config.json.
func NewObjectsClient(ctx context.Context, configPath string) (*objects.APIClient, error) {
	client := &scm.Client{
		AuthFile:         configPath,
		CheckEnvironment: false,
	}
	if err := client.Setup(); err != nil {
		return nil, err
	}
	if err := client.RefreshJwt(ctx); err != nil {
		return nil, err
	}

	cfg := objects.NewConfiguration()
	cfg.Host = client.GetHost()
	cfg.Scheme = "https"
	cfg.HTTPClient = client.HttpClient
	cfg.DefaultHeader = map[string]string{
		"Authorization": "Bearer " + client.Jwt,
		"x-auth-jwt":    client.Jwt,
	}

	return objects.NewAPIClient(cfg), nil
}

The same pattern applies to other packages (security_services, network_services, etc.). The scm-go README uses common.GetConfigPath() in its example; that helper lives in the repository’s test utilities and resolves to the repository’s own config/scm-config.json, so pass an explicit path in your own tools. [1]

Core CRUD patterns

The examples below are illustrative. Names and the 192.0.2.10 address (a reserved documentation range) are examples only. Method and field names match scm-go v1.0.13; the generated API can change between releases, so check the package you are using.

Helper:

go
func strPtr(s string) *string { return &s }

Create address object

go
req := api.AddressesAPI.CreateAddresses(ctx)
body := objects.Addresses{
	Name:        "web-server-01",
	Folder:      strPtr("Shared"),
	IpNetmask:   strPtr("192.0.2.10/32"), // documentation-range example (RFC 5737)
	Description: strPtr("web tier server"),
}
created, resp, err := req.Addresses(body).Execute()
if err != nil {
	// Inspect resp.StatusCode and response body for details
	return err
}
// created.Id contains the new object ID

List addresses (for idempotency checks)

go
list, _, err := api.AddressesAPI.ListAddresses(ctx).Folder("Shared").Execute()
if err != nil {
	return err
}
for _, addr := range list.Data {
	// addr.Name, addr.Id, addr.IpNetmask, etc.
}

Update address

go
existing, _, err := api.AddressesAPI.GetAddressesByID(ctx, id).Execute()
if err != nil {
	return err
}
existing.Description = strPtr("updated description")
_, _, err = api.AddressesAPI.UpdateAddressesByID(ctx, id).Addresses(*existing).Execute()

Delete address

go
_, err = api.AddressesAPI.DeleteAddressesByID(ctx, id).Execute()

Create tag

go
tagReq := api.TagsAPI.CreateTags(ctx)
tagBody := objects.Tags{
	Name:   "env-prod",
	Folder: strPtr("Shared"),
	Color:  strPtr("Red"),
}
_, _, err = tagReq.Tags(tagBody).Execute()

Create security rule

go
import sec "github.com/paloaltonetworks/scm-go/generated/security_services"

// Initialize secApi the same way as the objects client (inject JWT)
ruleReq := secApi.SecurityRulesAPI.CreateSecurityRules(ctx).Position("pre") // position is required
ruleBody := sec.SecurityRules{
	Name:        strPtr("allow-web-to-app"),
	Folder:      strPtr("Shared"),
	From:        []string{"trust"},
	To:          []string{"untrust"},
	Source:      []string{"any"},
	Destination: []string{"web-server-01"},
	Application: []string{"ssl", "web-browsing"},
	Service:     []string{"application-default"},
	Action:      strPtr("allow"),
	Description: strPtr("allow web traffic to application servers"),
}
createdRule, _, err := ruleReq.SecurityRules(ruleBody).Execute()

Create NAT rule (network_services package)

go
import netsec "github.com/paloaltonetworks/scm-go/generated/network_services"

// Initialize netApi similarly
natReq := netApi.NATRulesAPI.CreateNatRules(ctx).Position("pre") // position is required
natBody := netsec.NatRules{
	Name:        "web-inbound-nat",
	Folder:      strPtr("Shared"),
	From:        []string{"untrust"},
	To:          []string{"untrust"},
	Source:      []string{"any"},
	Destination: []string{"any"},
	Service:     "service-http",
	// Destination translation fields depend on the exact model version
}
_, _, err = natReq.NatRules(natBody).Execute()

JWT token caching

The SCM authentication API has rate limits on token requests (approximately 10 concurrent requests per tenant, according to the scm-go README). [1] For parallel or frequent operations, cache the JWT in the configuration file. scm-go reads these fields from scm-config.json starting with version 1.0.8: [1], [3]

json
{
  "client_id": "<your-client-id>",
  "client_secret": "<your-client-secret>",
  "scope": "tsg_id:<your-tsg-id>",
  "jwt": "<cached-jwt>",
  "jwt_expires_at": "2026-10-28T02:00:00Z",
  "jwt_lifetime": 900
}

A background process can refresh the token every 10–12 minutes and write it atomically. Client instances then read the cached token and avoid additional authentication calls. [1] Note that RefreshJwt always requests a new token, so a client that loaded a cached token should skip RefreshJwt while that token is still valid. [3]

Only share tokens among clients that use the same client ID and secret.

Common use cases

Use caseImplementation approach
Use caseApplication onboardingImplementation approachCreate address objects, tags, and security rules in sequence
Use caseEmergency blockImplementation approachCreate a high-priority deny rule; delete or disable it after the incident
Use caseEnvironment promotionImplementation approachList objects/rules from a source folder and recreate them in a target folder
Use caseBulk standardizationImplementation approachList resources, filter by criteria, and issue update calls
Use caseMulti-cloud consistencyImplementation approachApply the same object and rule definitions across folders associated with different device types
Use caseCI/CD integrationImplementation approachTrigger Go or Terraform runs on merge or approval
Use caseDrift detectionImplementation approachPeriodically list configuration and compare against a source of truth

Implementation notes

  • Configuration objects are scoped to a location: Folder, Snippet, or Device.
  • Prefer list-then-create/update patterns for idempotency.
  • Generated clients return the HTTP response; check status codes and parse error bodies on failure.
  • The SDK is auto-generated and community-supported. Validate behavior in a non-production tenant. [1], [2]
  • For large-scale declarative management, the Terraform provider is often a better fit than imperative scripts.
  • ZTNA Connector calls require the region set in the x_panw_region configuration field, which scm-go sends as the x-panw-region header (americas, europe, or apac). [1]

Generated package overview

PackagePrimary resources
PackageobjectsPrimary resourcesAddresses, groups, services, tags, applications, EDLs, HIP, schedules
Packagesecurity_servicesPrimary resourcesSecurity rules, profiles (anti-spyware, URL, file blocking, decryption, etc.)
Packagenetwork_servicesPrimary resourcesInterfaces, zones, NAT, PBF, IKE/IPsec, BGP, SD-WAN
Packageconfig_setupPrimary resourcesFolders, snippets, devices, variables, labels
Packagedeployment_servicesPrimary resourcesRemote networks, bandwidth, service connections
Packageztna_connector_allPrimary resourcesZTNA Connector configuration

scm-go v1.0.13 also includes config_operations, device_settings, identity_services, and mobile_agent packages. [9]

References

  1. Palo Alto Networks, scm-go repository and README. https://github.com/PaloAltoNetworks/scm-go
  2. Palo Alto Networks, scm-go support policy (community supported). https://github.com/PaloAltoNetworks/scm-go/blob/main/SUPPORT.md
  3. Palo Alto Networks, scm-go client.go (configuration loading and JWT handling). https://github.com/PaloAltoNetworks/scm-go/blob/main/client.go
  4. Terraform Registry, PaloAltoNetworks/scm provider. https://registry.terraform.io/providers/PaloAltoNetworks/scm/latest
  5. Palo Alto Networks, terraform-provider-scm go.mod (depends on scm-go). https://github.com/PaloAltoNetworks/terraform-provider-scm/blob/main/go.mod
  6. Palo Alto Networks, scm-python repository and README. https://github.com/PaloAltoNetworks/scm-python
  7. pan-scm-sdk repository. https://github.com/cdot65/pan-scm-sdk
  8. Palo Alto Networks, Strata Cloud Manager API documentation. https://pan.dev/scm/docs/home/
  9. Palo Alto Networks, scm-go generated packages. https://github.com/PaloAltoNetworks/scm-go/tree/main/generated

Diagram