User Tools

Site Tools


project_deep_dive

Projects & Policies — ZEDCloud Terraform

A practical guide to how projects, deployments, and policies fit together in this Terraform config, written against the zededa/zedcloud provider.

💡 TL;DR — A project groups devices and applies tenant-level policies. A deployment is a tag-driven template that auto-provisions config (networks, volumes, apps, attestation) onto every device carrying a matching tag. The matching is: device tags key/value == policy policy_target_condition key/value.

1. Mental model

Project (TAG_TYPE_PROJECT | TAG_TYPE_DEPLOYMENT)
│
├── tenant-level policies          → edgeview, attestation, configuration-lock
│
└── Deployment (zedcloud_deployment)
    ├── deployment_tag             → deployment-wide device selector (a single string)
    └── policies (per-policy device selector via policy_target_condition):
        ├── device_policies        → attestation (accept / enforce)
        ├── network_inst_policies  → auto-create a Network Instance per matching device
        ├── volume_inst_policies   → auto-create a Volume Instance per matching device
        ├── app_inst_policies      → auto-create an App Instance per matching device
        ├── cluster_policy
        ├── edgeview_policy
        └── integration_policy

The key difference from a standalone resource (e.g. a single zedcloud_volume_instance pinned to one node via device_id): a policy is a template. ZEDCloud stamps out a copy on every device that matches the policy's condition, instead of one explicit instance.


2. Projects (zedcloud_project)

A project is the top-level container for devices and the policies applied to them.

Project types

type Purpose
TAG_TYPE_PROJECT Standard project that owns edge nodes, apps, networks, etc.
TAG_TYPE_DEPLOYMENT Project used as the home for zedcloud_deployment resources.

In this repo:

  • demo_zededa_project_1 (TF-ZEDEDA-DEMO) — TAG_TYPE_PROJECT, owns the edge nodes.
  • demo_zededa_project_2 (TF-DEPLOY-PROJ-1) — TAG_TYPE_DEPLOYMENT, home of the deployment.

Project-level policy blocks

Block What it controls
tag_level_settings Interface ordering, flow-log transmission.
edgeview_policy Whether EdgeView remote access is allowed, session limits, JWT settings.
attestation_policy Tenant-level TPM attestation acceptance.
configuration_lock_policy Whether device config can be locked.

Example (deployment-type project)

resource "zedcloud_project" "demo_zededa_project_2" {
  name  = "TF-DEPLOY-PROJ-1"
  title = "TF-DEPLOY-PROJ-1"
  type  = "TAG_TYPE_DEPLOYMENT"
 
  tag_level_settings {
    interface_ordering    = "INTERFACE_ORDERING_ENABLED"
    flow_log_transmission = "NETWORK_INSTANCE_FLOW_LOG_TRANSMISSION_ENABLED"
  }
 
  configuration_lock_policy {
    type = "POLICY_TYPE_CONFIGURATION_LOCK"
    configuration_lock_policy {
      config_lock = "CONFIGURATION_LOCK_DISABLED"
    }
  }
 
  attestation_policy {
    type = "POLICY_TYPE_ATTESTATION"
    attestation_policy {
      type = "ATTEST_POLICY_TYPE_ACCEPT"
    }
  }
 
  edgeview_policy {
    type = "POLICY_TYPE_EDGEVIEW"
    edgeview_policy {
      access_allow_change = true
      edgeview_allow      = true
      edgeviewcfg {
        app_policy { allow_app = true }
        dev_policy { allow_dev = true }
        jwt_info {
          disp_url  = "zedcloud.gmwtus.zededa.net/api/v1/edge-view"
          allow_sec = 18000
          num_inst  = 1
          encrypt   = false   # see gotcha below
        }
        ext_policy { allow_ext = true }
      }
      max_expire_sec = 2592000
      max_inst       = 3
    }
  }
}
⚠️ EdgeView encryption gotcha. Setting encrypt = true in jwt_info fails with: policy validation failed: edgeview policy: Edgeview Encryption is not supported and cannot be enabled (HTTP 400). EdgeView encryption is not supported on this tenant — keep encrypt = false.

3. Attestation: ACCEPT vs ENFORCE

Attestation appears at two levels (project attestation_policy and deployment device_policies). The semantics, straight from the provider enum docs:

Value Meaning
…_ACCEPT Do not enforce attestation. All devices are marked as successfully attested (bypass).
…_ENFORCE Enforce attestation. Devices failing TPM attestation are marked accordingly.
Note: A device policy can only be attestation — the policy_sub_type enum has just DEVICE_POLICY_TYPE_UNSPECIFIED and DEVICE_POLICY_TYPE_ATTESTATION.

4. Deployments (zedcloud_deployment)

A deployment lives in a TAG_TYPE_DEPLOYMENT project and carries one or more policy blocks. Each policy is a template applied to devices matching its condition.

The two selectors — don't confuse them

Scope Field Type Role
Whole deployment deployment_tag single string Deployment-wide device selector / label.
Each policy policy_target_condition key/value map Per-policy device selector — this is what gates each policy.

They do not have to be equal. In this repo they are deliberately different (deployment_tag = “mc-edge-dep-tag” vs policy_target_condition = { demo = “mc-app-auto-dep” }).

THE ONE RULE

🔑 device's tags key/value == policy's policy_target_condition key/value

A policy fires on a device only if the device's tags map contains the exact key/value pair in that policy's policy_target_condition.
⚠️ Tag values are strings. A device tag written as device-tag-1 = true becomes the string “true”, so the condition must be quoted: policy_target_condition = { device-tag-1 = “true” }.

Policy blocks

Block Auto-creates per matching device Key config
device_policies (no object) sets attestation accept/enforce attestation_policy.type
network_inst_policies a Network Instance net_inst_config (kind, type, port)
volume_inst_policies a Volume Instance vol_inst_config (type, size, accessmode)
app_inst_policies an App Instance app id, drives, interfaces

Network instance kinds (quick reference)

kind Behaviour
NETWORK_INSTANCE_KIND_SWITCH Transparent L2 bridge. No DHCP/NAT — apps get direct access to the port.
NETWORK_INSTANCE_KIND_LOCAL L3 with DHCP + NAT managed by EVE.

5. Worked example — target a single device

Step 1 — tag the device

resource "zedcloud_edgenode" "demo_asus_nuc_zks_1" {
  # ...
  tags = {
    cluster      = "zed-cluster-1"
    device-tag-1 = true            # selector for the deployment policies
  }
}

Step 2 — write policies whose condition matches that tag

resource "zedcloud_deployment" "demo_eve_deployment_1" {
  name           = "TF-MC-DEPLOYMENT-TESTING"
  title          = "TF-MC-DEPLOYMENT-TESTING"
  project_id     = zedcloud_project.demo_zededa_project_2.id
  deployment_tag = "mc-edge-dep-tag"        # deployment label — independent of the match below
 
  device_policies {
    policy_sub_type = "DEVICE_POLICY_TYPE_ATTESTATION"
    attestation_policy { type = "DEVICE_ATTEST_POLICY_TYPE_ACCEPT" }
    meta_data {
      name = "TF-DEPLOY-PROJ-1"
      policy_target_condition = { device-tag-1 = "true" }
    }
  }
 
  network_inst_policies {
    meta_data {
      name = "TF-APP-NI"
      policy_target_condition = { device-tag-1 = "true" }
    }
    net_inst_config {
      kind = "NETWORK_INSTANCE_KIND_SWITCH"
      type = "NETWORK_INSTANCE_DHCP_TYPE_UNSPECIFIED"
      port = "eth1"
      tags = { demo = "app-ni" }   # label applied TO the created NI (not a selector)
    }
  }
 
  volume_inst_policies {
    meta_data {
      name = "TF-AUTO-VOL-1"
      policy_target_condition = { device-tag-1 = "true" }
    }
    vol_inst_config {
      label       = "TF-VOL-1-LABEL"
      type        = "VOLUME_INSTANCE_TYPE_BLOCKSTORAGE"
      accessmode  = "VOLUME_INSTANCE_ACCESS_MODE_READWRITE"
      cleartext   = false
      size_bytes  = 1073741824     # 1 GiB
      multiattach = false
    }
  }
}

Result

On demo_asus_nuc_zks_1 (because it has device-tag-1 = true):

  • attestation is bypassed (ACCEPT),
  • a SWITCH network instance is created on eth1,
  • a 1 GiB read-write block volume is created.

Devices without device-tag-1 = true get nothing from these policies.

Note: Networks + volumes alone don't run anything. Add an app_inst_policies block (or a standalone zedcloud_application_instance) for an actual app to land on the device and consume the NI + volume.

6. Standalone instance vs policy — when to use which

Standalone resource Policy in a deployment
Resource zedcloud_volume_instance, zedcloud_network_instance, zedcloud_application_instance *_inst_policies block inside zedcloud_deployment
Targeting Explicit: device_id (one node) or edge_node_cluster { id } (one cluster) Tag-based: every device matching policy_target_condition
Use when You want one specific instance on a known node/cluster You want the same config rolled out to a tagged fleet

Targeting a standalone instance

# single node
device_id = zedcloud_edgenode.demo_en_advantech_1.id
 
# OR a cluster (mutually exclusive with device_id)
edge_node_cluster {
  id = zedcloud_edgenode_cluster.demo_edgenode_cluster_1.id
}

7. Common errors & fixes

Error Cause Fix
Edgeview Encryption is not supported and cannot be enabled (HTTP 400) encrypt = true in a project/deployment edgeview jwt_info Set encrypt = false.
Reference to undeclared resource … zedcloud_edgecluster Wrong resource type/name for a cluster Use zedcloud_edgenode_cluster.<name>.id.
volume instance update error: [PUT …/instances/id/…][400] (empty message) An immutable field (type, size_bytes, accessmode, placement target) was changed on an existing volume; provider issues a PUT the API rejects terraform apply -replace='<resource>' (destroys volume data) or revert HCL to the original values.
Deployment policy provisions nothing No device carries the policy_target_condition tag Add the matching key = “value” to the target nodes' tags.
Note: On volume instances, only name is ForceNew in the provider schema — every other field is treated as updatable by Terraform even though ZEDCloud rejects changing it. That's why immutable changes surface as a runtime 400 rather than a plan-time “forces replacement”.

8. Glossary

Term Meaning
Project Top-level container for devices and tenant policies.
Deployment Tag-driven bundle of policies that auto-provision config onto matching devices.
deployment_tag Deployment-wide device selector / label (single string).
policy_target_condition Per-policy device selector (key/value map). The primary match.
device tags Key/value pairs on a zedcloud_edgenode; what conditions match against.
Attestation ACCEPT Bypass TPM attestation; mark all devices attested.
Attestation ENFORCE Require TPM attestation; flag failures.
SWITCH network instance Transparent L2 bridge (no DHCP/NAT).
Standalone instance An explicitly-placed volume/network/app pinned to one node or cluster.
project_deep_dive.txt · Last modified: by 127.0.0.1