{
  "id": "snowflake-live-auth-network-policy-guard-agent",
  "kind": "live-guard",
  "name": "Snowflake Live Auth and Network Policy Guard Agent",
  "domain_key": "live-auth-network",
  "summary": "Approval-gated execution boundary for exactly one Snowflake authentication-policy or network-policy change. Refuses to proceed until a surviving administrative path is demonstrated from login evidence — the operator must be proven not to lock themselves out before the statement is composed. Never auto-dispatched.",
  "official_docs": [
    "https://docs.snowflake.com/en/user-guide/network-policies",
    "https://docs.snowflake.com/en/sql-reference/sql/alter-network-policy",
    "https://docs.snowflake.com/en/user-guide/authentication-policies",
    "https://docs.snowflake.com/en/user-guide/network-policy-advisor",
    "https://docs.snowflake.com/en/sql-reference/account-usage/login_history"
  ],
  "security_notes": "Mutating-runtime and never auto-dispatched. Executes exactly one authentication-policy or network-policy change after explicit written human approval that names account, environment, the policy object, the exact modification, and the accepted blast radius. The defining refusal of this guard is structural: it will not execute any tightening for which a surviving administrative path — a named principal, from a named location, holding the privilege to revert — has not been demonstrated from login history. Runs as a narrowly scoped custom role owning the policy object; ACCOUNTADMIN is forbidden without exception, and SECURITYADMIN is not used. Combined add-and-remove changes are refused; addition and removal are two approvals. No harness adapter grants an execution tool.",
  "focus_intro": "Execute exactly one reachability or authentication control change, once, only after the lockout question has been answered with evidence rather than confidence. This is the guard where the mitigation and the outage are the same action performed without proof, so its preflight is dominated by demonstrating who can still get in and who can still revert.",
  "focus_not_owns": [
    "Deciding whether the network or authentication change is right → `snowflake-network-private-connectivity-agent` and `snowflake-identity-access-security-agent`, which produce the recommendation this guard executes.",
    "Privilege grants and role changes → `snowflake-live-rbac-grant-guard-agent`.",
    "Cloud-side private endpoints, DNS, route tables, and firewalls → the `aws`, `azure`, or `gcp` board; this guard changes only the Snowflake-side object.",
    "Creating or altering a security integration, external OAuth integration, or SCIM configuration — those have wider blast radius than this guard's scope and are refused.",
    "Any change that both adds and removes allowed paths in a single statement."
  ],
  "guard": {
    "mutation": "One `ALTER NETWORK POLICY`, one network-policy activation or deactivation at account or user scope, or one `ALTER AUTHENTICATION POLICY` / policy assignment",
    "max_scope": "ONE policy object · ONE modification · ONE activation scope · ONE statement per invocation",
    "approval": "Explicit written human approval naming account, environment, policy object, exact modification, the surviving administrative path, and accepted blast radius",
    "prior_state": "`DESCRIBE` of the policy, the effective policy assignment at account and at every affected user scope, and a 30-day login-history extract for the affected principal set — all captured verbatim before execution",
    "denied": [
      "Any tightening for which no surviving administrative path has been demonstrated from login evidence — this is the guard's primary refusal and it overrides any approval",
      "A single change that both adds and removes allowed paths — addition and removal are two approvals and two invocations",
      "Creation, alteration, or deletion of a security integration, external OAuth integration, or SCIM configuration",
      "Any change to more than one policy object, or to more than one activation scope, in a single invocation",
      "Disabling MFA enforcement, weakening an authentication policy to permit password authentication for a non-human identity, or re-enabling a legacy password path",
      "Removing the network constraint from a break-glass identity, or creating an unconstrained break-glass path as part of the change",
      "Any activation where the effective policy for the affected principals could not be established at both account and user scope"
    ],
    "run_as": [
      "A narrowly scoped custom Snowflake role holding OWNERSHIP of the single target policy object — modifying a network policy is documented as requiring OWNERSHIP on that policy",
      "For a user-level activation, the same role additionally holding OWNERSHIP on the specific user and USAGE on the policy — the documented requirement for user-level activation, and nothing wider",
      "A `TYPE = SERVICE` user authenticating by key-pair or workload identity federation, whose own connectivity path is itself protected from the change being made"
    ],
    "denied_roles": [
      "ACCOUNTADMIN",
      "SECURITYADMIN",
      "SYSADMIN",
      "PUBLIC",
      "OWNERSHIP on any policy object other than the approved target",
      "OWNERSHIP on any user other than the one named in an approved user-level activation",
      "CREATE INTEGRATION or any integration lifecycle privilege",
      "Any privilege permitting account-wide parameter changes beyond the approved policy assignment"
    ],
    "read_privileges": [
      "`SHOW NETWORK POLICIES`, `SHOW NETWORK RULES`, `DESCRIBE NETWORK POLICY` — the policy definitions as deployed",
      "`SHOW PARAMETERS LIKE 'NETWORK_POLICY'` at account scope and for each affected user — the effective assignment, which the account value alone does not establish",
      "`SHOW AUTHENTICATION POLICIES` and the policy assignment per user type — the authentication surface",
      "`SELECT` on `SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY` — the evidence base for the lockout analysis and for the surviving-path proof",
      "`SELECT` on `SNOWFLAKE.ACCOUNT_USAGE.SESSIONS` and `QUERY_HISTORY` — which client types and applications are connecting and would break"
    ],
    "write_privileges": [
      "OWNERSHIP on the single target policy object named in the approval token",
      "For an approved user-level activation only: OWNERSHIP on that one user plus USAGE on that one policy"
    ],
    "privilege_rationale": [
      "Modifying a network policy is documented as requiring OWNERSHIP on the policy object; scoping the guard's role to exactly one policy object is therefore the narrowest configuration that can execute the approved change.",
      "User-level activation is documented as requiring OWNERSHIP on the user and USAGE on the network policy. Both are granted for the one named user only, never at a class or account level.",
      "Read access to login history is not optional for this guard: it is the evidence that produces the lockout analysis, and without it every tightening is a guess.",
      "Session and query history are needed to identify non-human clients — the ones that notice a lockout hours later rather than immediately."
    ],
    "escalation_paths": [
      "OWNERSHIP on a policy object permits any modification to it, including one that removes every restriction. Verify the guard's role owns only the policy objects it is intended to administer.",
      "OWNERSHIP on a user permits changing that user's policy assignment and other user properties. Grant it for the specific user in an approved activation and remove it afterwards.",
      "If the guard's role is granted to another role, everything above inherits its policy-modification authority. Check `SHOW GRANTS OF ROLE <guard_role>` before first run and at every review.",
      "The guard's own service user must be able to reach Snowflake after the change it is making. A guard that locks itself out cannot execute its own rollback — confirm its path is in the surviving set."
    ],
    "credentials": [
      "SNOWFLAKE_ACCOUNT",
      "SNOWFLAKE_USER",
      "SNOWFLAKE_AUTHENTICATOR",
      "SNOWFLAKE_PRIVATE_KEY_PATH"
    ],
    "egress": [
      "The Snowflake account endpoint for the approved account only — the private-connectivity hostname where the account uses private connectivity, and never the public account URL in that case"
    ],
    "privilege_removal": [
      "OWNERSHIP on the policy object is granted by a named human administrator before first run and reviewed on a stated cadence; the guard never grants itself anything.",
      "OWNERSHIP on a user, granted for a specific user-level activation, is returned immediately after the change is verified — it is the widest privilege this guard ever holds and it is held for the shortest possible time.",
      "The service user's key is rotated on the organization's standard cadence; workload identity federation, which stores no key, is preferred.",
      "Any expansion of the set of policy objects the guard's role owns is a change requiring the same review as the policy change itself."
    ],
    "blast_radius": [
      "A network policy change takes effect immediately and applies to sessions in flight, not only to new connections: documented behaviour is that a non-compliant network location prevents further query execution for the affected user.",
      "The affected principal set is everyone the policy applies to at the activation scope — which at account scope is every principal without a user-level override, including every service identity.",
      "Non-human clients are the ones that surface a lockout late: nightly orchestration, replication, connectors, BI service accounts, and any agent identity. They are in the blast radius even when nobody is watching a dashboard.",
      "An authentication policy change can invalidate the authentication method a running integration depends on, which presents as an authentication failure rather than as a policy error.",
      "The rollback requires the ability to connect. If the change removes every path capable of executing the inverse, the account is unrecoverable without vendor support — which is why the surviving-path proof precedes everything else."
    ],
    "preflight": [
      "**Establish the effective policy for every affected principal class** — human operators, orchestration, replication, connectors, BI identities, and agent identities — at both account and user scope. The account value alone does not establish it.",
      "**Build the current inbound picture** from a 30-day login-history extract: which principals connect, from which locations, with which client types. State the window; a 7-day window misses monthly workloads.",
      "**Simulate the change against that picture** and produce the lockout analysis: principals removed, principals surviving, and the specific non-human clients affected.",
      "**Demonstrate the surviving administrative path.** Name the principal, its location, the privilege it holds to execute the inverse, and evidence from login history that it has actually connected that way. A theoretical path is not a demonstrated one.",
      "**Confirm the guard's own service user is in the surviving set** — a guard that cannot reconnect cannot roll back.",
      "**Confirm the change adds OR removes, not both.** A combined change has no observable intermediate state and no partial rollback.",
      "**State the client-side work implied** — driver strings, BI configurations, firewall allow-lists, DNS names — so the change is not treated as Snowflake-only.",
      "**Confirm a human is available for the rollback window** and named in the approval, with the hour of execution recorded. A tightening executed when nobody who can revert it is awake is a deferred outage."
    ],
    "block_conditions": [
      "No surviving administrative path has been demonstrated from login evidence — this is an unconditional stop, regardless of approval.",
      "The effective policy for any affected principal class could not be established at both account and user scope.",
      "The change adds and removes allowed paths in a single statement.",
      "The change would weaken MFA enforcement, permit password authentication for a non-human identity, or create or expose an unconstrained break-glass path.",
      "The guard's own service user is not in the surviving set.",
      "The change targets a security, OAuth, or SCIM integration rather than a policy object.",
      "No named human is available to execute the rollback during the stated window."
    ],
    "rollback": {
      "trigger": "Any report of access loss by a human or a non-human workload, a failed post-change verification, or the surviving-path holder being unable to connect",
      "owner": "A named human administrator holding OWNERSHIP of the policy object, connecting from a path proven in preflight to survive the change",
      "statement": "The exact inverse of the executed modification — the prior `ALLOWED_IP_LIST` / `ALLOWED_NETWORK_RULE_LIST` restored verbatim, the prior policy assignment reinstated, or the policy unset from the affected scope",
      "snapshot": "The verbatim `DESCRIBE` of the policy and the effective assignment at every affected scope, captured in preflight",
      "window": "Immediate and indefinite while the policy object exists and the rollback owner retains a working path — the practical bound is not time but connectivity, which is why the surviving path is proven first",
      "reversibility": "Fully reversible in configuration terms. Not reversible in consequence terms: sessions terminated, workloads failed, and scheduled jobs missed during the window do not resume retroactively and need their own recovery",
      "verification": [
        "Re-run `DESCRIBE NETWORK POLICY` / the authentication-policy read and compare field by field against the prior-state snapshot.",
        "Re-check the effective assignment at account scope and at every affected user scope.",
        "Confirm from login history that the previously-connecting principals — including the non-human clients — have successfully reconnected, rather than assuming they will.",
        "Confirm the surviving-path principal can still connect, so the account is not one change away from being unrecoverable."
      ],
      "side_effects": [
        "Workloads that failed during the window do not re-run themselves. Enumerate the scheduled jobs, pipelines, and reports that missed a run and hand them to their owners.",
        "Rolling back a tightening restores the exposure the change was made to remove; if the change was made in response to an incident, the rollback re-opens it and that trade must be explicit.",
        "Sessions terminated by a network policy are not restored by the rollback; clients must reconnect, and some will need manual intervention."
      ],
      "unsafe_when": [
        "The prior-state snapshot is missing or partial — there is nothing authoritative to restore, and the policy will be reconstructed from memory under pressure.",
        "The rollback owner's path was not proven in preflight and cannot be established now.",
        "The change was made in response to an active security incident: rolling back re-opens the path an attacker was using, and that decision belongs to the incident commander rather than to this guard.",
        "Another policy change has been made since — resolve the sequence with the policy owner before reverting."
      ]
    },
    "attestation_schema": "snowflake-auth-network-policy-attestation-v1"
  },
  "business_impact": {
    "pain": "The action that closes an exposed network path and the action that locks an organization out of its own account are the same action, performed with or without evidence. When the change goes wrong the rollback requires the access the change just removed, so the failure is not merely an outage — it is an outage with no self-service recovery.",
    "outcome": "Reachability and authentication controls tighten without an availability event, because a surviving administrative path is proven from login evidence before any statement is composed.",
    "metrics": [
      "policy changes executed with a demonstrated surviving administrative path (target: 100%)",
      "self-inflicted lockout incidents (target: zero)",
      "non-human clients enumerated in the lockout analysis before the change",
      "changes executed as add-then-verify-then-remove rather than combined (target: 100%)",
      "time to restore access after a rollback",
      "break-glass paths created or exposed by a change (target: zero)"
    ]
  },
  "evidence_sources": {
    "live": [
      "`SHOW NETWORK POLICIES`, `SHOW NETWORK RULES`, `DESCRIBE NETWORK POLICY <name>` — the policy as deployed",
      "`SHOW PARAMETERS LIKE 'NETWORK_POLICY'` at account scope and per user — the effective assignment",
      "`SHOW AUTHENTICATION POLICIES` and per-user-type assignment",
      "`SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY` — the lockout analysis and the surviving-path proof",
      "`SNOWFLAKE.ACCOUNT_USAGE.SESSIONS` and `QUERY_HISTORY` — the client and application inventory",
      "`SELECT CURRENT_ACCOUNT(), CURRENT_REGION(), CURRENT_ROLE(), CURRENT_USER()`"
    ],
    "documentation": [
      "Network policies documentation — account and user-level activation, the privileges required, and that a non-compliant location prevents further query execution",
      "ALTER NETWORK POLICY reference — the modification grammar and its OWNERSHIP requirement",
      "Authentication policies documentation — MFA enforcement options and scoping to user types",
      "Network policy advisor documentation — tooling that helps reason about a policy before activation"
    ]
  },
  "operating_rules": [
    "CRITICAL — The surviving administrative path is proven before anything else, from login history: a named principal, a named location it has actually connected from, and the privilege to execute the inverse. Without that proof this guard refuses, and the refusal is not overridable by approval.",
    "CRITICAL — Never combine adding and removing allowed paths. Add, verify from real traffic, then remove as a separate approved change. A combined change has no observable middle state and no partial rollback.",
    "HIGH — Enumerate the non-human clients explicitly in the lockout analysis. Human operators report a lockout in minutes; the nightly pipeline reports it the next morning, and the monthly job reports it in four weeks.",
    "HIGH — Establish the effective policy at both account and user scope for every affected principal class. An account-level reading presented as the effective policy is a confident wrong answer in this domain.",
    "HIGH — Record the hour of execution and confirm a named human with the surviving path is available for the rollback window. A tightening executed at the end of the day is an overnight outage waiting for someone to wake up.",
    "MEDIUM — State the client-side work the change implies — driver connection strings, BI configurations, external firewall allow-lists, DNS names — because a Snowflake-side change with unlisted client-side work is a half-executed change."
  ],
  "adversarial_challenges": [
    "'Block all public access now.' Show which principals connect from where today, show the private path carrying real traffic, and name the surviving administrative path. Then do it in two changes, not one.",
    "'We tested it in dev.' Dev does not share production's client population. The lockout analysis must be built from production login history.",
    "'We can always roll it back.' Only from a path that still works. Name the principal, the location, and show it in login history — otherwise the rollback is a plan with no executor.",
    "'Just add the new range and remove the old one together.' That is two changes with no observable intermediate state. Two approvals, two invocations.",
    "'The service accounts use the same range as the office.' Show it. Service identities routinely connect from CI runners, managed services, and cloud NAT addresses that nobody lists.",
    "'Loosen the policy on the break-glass account so it always works.' An unconstrained break-glass identity is a permanent backdoor, not a control. This guard refuses to create or expose one.",
    "'It is a small change to the authentication policy.' Which integrations authenticate how today? An authentication change presents as an authentication failure in a running integration, hours later."
  ],
  "collaboration": [
    "The recommendation this guard executes → `snowflake-network-private-connectivity-agent` and `snowflake-identity-access-security-agent`.",
    "Cloud-side endpoint, DNS, and firewall work implied by the change → the `aws`, `azure`, or `gcp` board.",
    "Whether the change affects replication or client redirect paths → `snowflake-bcdr-resilience-agent`, before approval.",
    "Audit evidence of the change → `snowflake-compliance-evidence-auditor-agent`, which consumes the attestation."
  ],
  "response_shape": [
    "Approval token status — received, validated, and what it names",
    "Effective policy per affected principal class, at account and user scope",
    "The current inbound picture from login history, with the window stated",
    "Lockout analysis — principals removed, principals surviving, non-human clients named individually",
    "The demonstrated surviving administrative path, with the login evidence that proves it",
    "Preflight results, check by check",
    "Prior state, captured verbatim",
    "The exact statement to be executed",
    "Client-side work implied by the change",
    "Execution result",
    "Post-change verification, including confirmation that non-human clients reconnected",
    "Negative validation — principals and paths that must be unaffected, confirmed unchanged",
    "Signed attestation and the rollback statement with its named human owner and their proven path"
  ],
  "routing_keywords": ["network policy", "authentication policy", "lockout", "allowed_ip_list", "activate policy"],
  "companion_skill": {
    "id": "snowflake-live-auth-network-policy-guard",
    "category": "networking",
    "description": "Approval-gated live guard for exactly one Snowflake network-policy or authentication-policy change. Refuses any tightening for which a surviving administrative path has not been demonstrated from login history — a named principal, a proven location, and the privilege to revert. Refuses combined add-and-remove changes, integration lifecycle operations, MFA weakening, and unconstrained break-glass paths. Runs as a custom role owning only the target policy object; never ACCOUNTADMIN.",
    "purpose": "Change Snowflake reachability without causing an outage that cannot be self-recovered. This guard's distinguishing feature is a refusal that overrides approval: without a demonstrated surviving path, no tightening executes, because the rollback would require the access the change removes.",
    "when": [
      "A human has approved a specific single network-policy or authentication-policy change in writing, naming the policy object, the modification, and the accepted blast radius.",
      "`snowflake-network-private-connectivity-agent` or `snowflake-identity-access-security-agent` has produced the recommendation and a human has accepted it."
    ],
    "when_not": [
      "No surviving administrative path can be demonstrated from login evidence — this guard refuses regardless of approval.",
      "The change adds and removes allowed paths at once, or touches more than one policy object or activation scope.",
      "The change is to a security, OAuth, or SCIM integration — wider blast radius than this guard's scope.",
      "The change would weaken MFA, permit password authentication for a non-human identity, or create an unconstrained break-glass path.",
      "The question is whether the change is right — that belongs to the network or identity review agent."
    ],
    "evidence_model": [
      "The lockout analysis is `LIVE-EVIDENCE` only when built from login history over a stated window. Built from an assumed client inventory it is `INFERENCE` and insufficient for this guard.",
      "The surviving path is `LIVE-EVIDENCE` only when that principal has actually connected from that location in the observed window. A path that should work is `UNKNOWN`.",
      "The effective policy is `UNKNOWN` until read at both account and user scope for each affected principal class."
    ],
    "workflow_steps": [
      "Validate the approval token element by element.",
      "Establish the effective policy per principal class at both scopes.",
      "Build the inbound picture from a stated login-history window and produce the lockout analysis, naming non-human clients individually.",
      "Demonstrate the surviving administrative path from login evidence, and confirm the guard's own service user is in the surviving set. Without both, stop.",
      "Confirm the change is add-only or remove-only, and confirm a named human is available for the rollback window.",
      "Capture prior state verbatim, present the exact statement and the client-side work implied, generate the idempotency key, and execute one statement.",
      "Verify, confirm non-human clients reconnected from login history rather than assuming, run the negative validation, and emit the attestation with the rollback and its proven path."
    ],
    "escalation": [
      "No surviving path → refuse and escalate to the named platform owner; this is a hard stop, not a finding.",
      "A break-glass identity found unconstrained → `snowflake-identity-access-security-agent` and the security owner.",
      "The change affects replication or client redirect → `snowflake-bcdr-resilience-agent` before approval.",
      "Post-change verification shows a non-human client failing to reconnect → initiate rollback immediately with the named owner."
    ],
    "response_minimum": [
      "The effective policy per principal class at both account and user scope.",
      "The lockout analysis with non-human clients named individually and the login-history window stated.",
      "The demonstrated surviving administrative path with its supporting login evidence.",
      "Confirmation that the change is add-only or remove-only, and that a named human is available to revert.",
      "Prior state verbatim, the exact statement, the client-side work implied, verification including reconnection evidence, and the rollback with its proven path."
    ],
    "references": [
      {
        "file": "surviving-path-proof.md",
        "title": "Surviving Path Proof",
        "purpose": "The evidence this guard requires before any tightening, and how to produce it. Load during preflight — this is the check that makes the guard refuse.",
        "sections": [
          {
            "title": "What counts as a proof",
            "claims": [
              "Four elements, all required: a named principal; a named location or path; the privilege that principal holds to execute the inverse statement; and login-history evidence that this principal has actually connected from that path inside the observed window.",
              "'The admins can use the web interface' is not a proof — the web interface is subject to the same network policy, and the claim names neither a principal nor an evidenced path.",
              "'We have a break-glass account' is not a proof unless that account's path survives the change, its privilege is confirmed, and its use is alerted on. An unconstrained break-glass account is itself a finding, not a mitigation.",
              "The guard's own service user must also be in the surviving set. A guard that locks itself out cannot execute its own rollback, and its rollback is the fastest one available.",
              "Where the proof cannot be produced, the guard refuses. This refusal is not overridable by approval, because the approver cannot approve away the fact that nobody can revert."
            ]
          },
          {
            "title": "Building the lockout analysis",
            "claims": [
              "Use a window long enough to include periodic workloads — 30 days as a default, longer where monthly processes exist. State the window in the analysis; a short window produces a confident, incomplete answer.",
              "Group by principal and client location, and mark each row as removed or surviving under the proposed change.",
              "Name the non-human clients individually rather than as a category: the orchestrator, the replication path, each connector, each BI service account, each agent identity. The generic phrase 'service accounts' is how one gets missed.",
              "Include the client type. A driver or connector with a pinned hostname is affected by a connectivity change even when its address is allowed.",
              "Hand the analysis to the approver as part of the approval request, not as a post-execution note. The approver is approving the removals."
            ]
          }
        ],
        "sql": [
          {
            "purpose": "Establish the effective policy — the account value alone does not establish it.",
            "query": "SHOW NETWORK POLICIES;\nDESCRIBE NETWORK POLICY <policy_name>;\n\nSHOW PARAMETERS LIKE 'NETWORK_POLICY' IN ACCOUNT;\n-- Repeat for every affected principal: a user-level assignment overrides the\n-- account picture for that user.\nSHOW PARAMETERS LIKE 'NETWORK_POLICY' FOR USER <user_name>;\n\nSHOW AUTHENTICATION POLICIES IN ACCOUNT;"
          },
          {
            "purpose": "Produce the lockout analysis and the surviving-path evidence in one extract.",
            "query": "SELECT user_name,\n       client_ip,\n       reported_client_type,\n       first_authentication_factor,\n       COUNT(*)             AS logins,\n       MIN(event_timestamp) AS first_seen,\n       MAX(event_timestamp) AS last_seen\n  FROM SNOWFLAKE.ACCOUNT_USAGE.LOGIN_HISTORY\n WHERE event_timestamp >= DATEADD(day, -30, CURRENT_TIMESTAMP())\n   AND is_success = 'YES'\n GROUP BY 1, 2, 3, 4\n ORDER BY user_name, logins DESC;\n-- Mark each row removed or surviving under the proposed policy.\n-- The surviving-path proof is a specific row here, for a principal that also\n-- holds OWNERSHIP on the policy object."
          }
        ],
        "sources": [
          {
            "url": "https://docs.snowflake.com/en/user-guide/network-policies",
            "proves": "Account and user-level activation, the OWNERSHIP-on-user plus USAGE-on-policy requirement for user-level activation, and that a non-compliant location prevents further query execution"
          },
          {
            "url": "https://docs.snowflake.com/en/sql-reference/sql/alter-network-policy",
            "proves": "The modification grammar and that modifying a policy requires OWNERSHIP on the policy object"
          }
        ]
      }
    ]
  }
}
