Running Security Intelligence Scout in Snowpark Container Services
Running Security Intelligence Scout inside your Snowflake account removes the infrastructure you would otherwise host the container on, and the Snowflake credential you would otherwise create, store, and rotate. The scout runs as a long-lived Snowpark Container Services service in the account it monitors, reads that account’s activity views locally, and sends the audit records it builds to ALTR.
The scout takes its task configuration from ALTR, not from anything you create in Snowflake. A Snowflake Agent Repository supports scan tasks over query activity and over login activity, selected per task with the Account Usage View field – create one task for each kind you want monitored.
Prerequisites
Section titled “Prerequisites”Before deploying the service:
-
The deployment assets:
deploy.sh, the numbered SQL files it runs, the service-specification template, andsis-spcs.env.example. Contact ALTR Support for the bundle matching the release you intend to run. -
The Snowflake CLI (
snow) with a connection configured for the target account, anddocker. Copying the image into the account usessnow spcs image-registry login. -
A role that can
USE ROLE ACCOUNTADMINin the target account. No lesser role can grantIMPORTED PRIVILEGES ON DATABASE SNOWFLAKE, which every scan depends on. -
An account that is not a trial account. Snowpark Container Services isn’t offered on trial accounts, and external network access is disabled there by default.
-
A compute pool instance family that exists in the account’s cloud provider and region. Families differ by cloud provider first and then by region, so run
SHOW COMPUTE POOL INSTANCE FAMILIESin the target account before you start:CREATE COMPUTE POOLnaming an unavailable family fails outright. Copy thelinux/amd64image, for whichCPU_X64_XSis available on all 3 cloud providers. -
The agent’s private key as a non-password-protected, PEM-encoded, PKCS#8 file – the
-----BEGIN PRIVATE KEY-----header. The scout reads no other form and takes no passphrase. Convert a PKCS#1 key (-----BEGIN RSA PRIVATE KEY-----) first:Terminal window (umask 077; openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \-in key.pem -out key-pkcs8.pem) -
The Agent ID, ALTR Organization ID, and Data Plane URL that ALTRNet displays after you register the agent. The service specification below reads all 3.
-
The Snowflake account registered as a repository in ALTR, with the agent registered and at least one scan task created – see Database Activity Monitoring with Agents. That half is the same for every deployment target. Each task’s schedule sets the scan cost: because
ACCOUNT_USAGElags 45 minutes for query history and 2 hours for login history regardless, a 1-minute schedule buys almost no freshness while costing roughly 2,880 queries a day for a pair of tasks, and a schedule in the tens of minutes delays activity by an amount the lag already dominates. -
The release of the scout you intend to run,
1.5.1or later – earlier releases carry no Snowflake support at all. ALTR publishes the image publicly atpublic.ecr.aws/altr/security-intelligence-scout.
How the Service Authenticates
Section titled “How the Service Authenticates”The service authenticates to Snowflake with a session token Snowflake mounts into the container, so the deployment creates no Snowflake user, password, or key pair. Snowflake writes the token to /snowflake/session/token and rotates it every few minutes, and the scout re-reads the file for each connection, so a rotation needs no restart.
This has 2 consequences that shape the rest of this page. A session opened this way has no user record behind it, so it runs as the role that owns the service: every privilege the scout needs at run time has to reach that role, and the service has to be created by that role rather than by ACCOUNTADMIN. The same absence of a user record means the session inherits no default warehouse, so the service names one explicitly.
The ALTR agent key is separate, and still required. It signs the scout’s requests to ALTR rather than to Snowflake, and stage 4 below stores it as a Snowflake secret.
Service Deployment
Section titled “Service Deployment”ALTR ships this deployment as a script. deploy.sh renders the numbered SQL files beside it, copies the image, and creates every object the deployment needs in one run – and it checks the configuration against what the account and the agent will accept before it sends anything. Run it wherever your environment can reach both Snowflake and Docker.
Deployment Configuration
Section titled “Deployment Configuration”The whole deployment’s configuration lives in one file beside the script. Copy sis-spcs.env.example to sis-spcs.env and fill it in:
| Setting | Value |
|---|---|
SNOW_CONNECTION |
The Snowflake CLI connection for the target account |
DEPLOY_USER |
The Snowflake user to grant SIS_SERVICE_ROLE to. It is granted as a quoted, case-sensitive identifier, so the value has to match SHOW USERS exactly |
SIS_ORG_ID |
The ALTR Organization ID, lowercase |
SIS_AGENT_ID |
The Agent ID from the agent’s registration |
SIS_HOSTNAME |
The host of the Data Plane URL, lowercase, with no scheme and no port |
SIS_CONFIG_BLOB_HOST |
The object-storage host ALTR’s pre-signed configuration URLs point at, as in stage 3. The value depends on which ALTR environment your organization is in – ask ALTR Support for yours |
ALTR_PRIVATE_KEY_FILE |
Path to the agent’s PKCS#8 private key file |
SIS_IMAGE_SOURCE |
The image to copy, public.ecr.aws/altr/security-intelligence-scout:<VERSION> |
SIS_IMAGE_VERSION |
The tag the image is pushed to inside the account, which the service specification then references |
SIS_IMAGE_PLATFORM |
linux/amd64, or linux/arm64 against an ARM instance family |
INSTANCE_FAMILY |
A family the account’s cloud provider and region offer, matching the platform |
SIS_SECRET_MODE |
file to mount the agent key into the container, or env to inject it as an environment variable. The stages below show file mode |
Deployment Run
Section titled “Deployment Run”A deployment run starts with a preview. --dry-run renders everything, prints the SQL that would run and the specification that would be staged, and sends nothing to Snowflake:
./deploy.sh --dry-runThen deploy:
./deploy.shThe script creates the account objects, copies the image, then runs the grants, the egress objects, the secret, and the compute pool, stages the specification, and creates the service.
--config <PATH> points at a configuration file kept elsewhere, --skip-image deploys without re-copying an image already in the account, and --rotate-secret replaces the stored agent key – see Agent Key Rotation.
Before it touches the account, the script refuses a configuration that would deploy something broken: a placeholder left unfilled, a SIS_HOSTNAME carrying a scheme or a port, an uppercase or non-ASCII value where the agent will dial a lowercase ASCII one, an agent key that is encrypted or PKCS#1 rather than PKCS#8, a SIS_ORG_ID or SIS_AGENT_ID that isn’t a well-formed UUID, and an image platform the instance family can’t schedule. Every one of those leaves a deployment whose objects all exist, and no error message reports it.
Deployment Stages
Section titled “Deployment Stages”Each stage is a step deploy.sh runs, given in full and in the order the objects depend on each other. The 6 numbered stages are the 6 numbered SQL files in the deployment assets; the 2 shell steps between them have no file of their own. Without the script, work through them in order as ACCOUNTADMIN except where a stage says otherwise, and check the configuration against the list in Deployment Run first: the script is the path ALTR tests, and a hand run skips its checks.
Each snow sql invocation opens a fresh session, so a stage that needs a particular role sets it in the same invocation.
1. Create the Account Objects
Section titled “1. Create the Account Objects”The account objects hold everything else the deployment creates: the image the service runs, the specification that defines it, and the warehouse its scan queries run on.
USE ROLE ACCOUNTADMIN;
CREATE DATABASE IF NOT EXISTS SIS_APP;CREATE SCHEMA IF NOT EXISTS SIS_APP.CORE;
CREATE IMAGE REPOSITORY IF NOT EXISTS SIS_APP.CORE.IMAGES;CREATE STAGE IF NOT EXISTS SIS_APP.CORE.SPECS;
CREATE WAREHOUSE IF NOT EXISTS SIS_WH WAREHOUSE_SIZE = 'XSMALL' AUTO_SUSPEND = 60 AUTO_RESUME = TRUE INITIALLY_SUSPENDED = TRUE;Snowpark Container Services pulls a service’s image only from an image repository inside the same account, which is why the deployment creates one here and copies the image into it next.
Copy the Container Image into the Account
Section titled “Copy the Container Image into the Account”Copying the image pushes it into the image repository from stage 1. Push as ACCOUNTADMIN, the role that owns the repository, or grant WRITE ON IMAGE REPOSITORY SIS_APP.CORE.IMAGES to the role your snow connection uses – READ alone lists and pulls but cannot push. Read the repository’s URL first, then push against it:
snow spcs image-repository url SIS_APP.CORE.IMAGES -c <CONNECTION_NAME>
snow spcs image-registry login -c <CONNECTION_NAME>docker pull --platform linux/amd64 public.ecr.aws/altr/security-intelligence-scout:<VERSION>docker tag public.ecr.aws/altr/security-intelligence-scout:<VERSION> <REPOSITORY_URL>/sis:<IMAGE_TAG>docker push <REPOSITORY_URL>/sis:<IMAGE_TAG>ALTR publishes the scout to public.ecr.aws/altr/security-intelligence-scout, which needs no credential to pull. <VERSION> is the release being deployed – a latest tag is published alongside the versioned ones, but use a specific version so an upgrade is something you decide rather than something a re-push does for you. <REPOSITORY_URL> is the value the first command returns. <IMAGE_TAG> is the tag the service specification references below, so use the same value in both.
2. Create the Service Role and Its Grants
Section titled “2. Create the Service Role and Its Grants”The service role is the identity the scout runs as, so every privilege it needs at run time is granted here. IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE is the load-bearing one: SNOWFLAKE.ACCOUNT_USAGE is exposed through a shared database, which needs that grant rather than a SELECT grant, and a scan without it fails with SQL state 42501. The scout reads only QUERY_HISTORY and LOGIN_HISTORY from that database.
USE ROLE ACCOUNTADMIN;
CREATE ROLE IF NOT EXISTS SIS_SERVICE_ROLE;
GRANT IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE TO ROLE SIS_SERVICE_ROLE;GRANT USAGE ON WAREHOUSE SIS_WH TO ROLE SIS_SERVICE_ROLE;GRANT USAGE ON DATABASE SIS_APP TO ROLE SIS_SERVICE_ROLE;GRANT USAGE ON SCHEMA SIS_APP.CORE TO ROLE SIS_SERVICE_ROLE;GRANT CREATE SERVICE ON SCHEMA SIS_APP.CORE TO ROLE SIS_SERVICE_ROLE;GRANT READ ON IMAGE REPOSITORY SIS_APP.CORE.IMAGES TO ROLE SIS_SERVICE_ROLE;GRANT READ ON STAGE SIS_APP.CORE.SPECS TO ROLE SIS_SERVICE_ROLE;
GRANT ROLE SIS_SERVICE_ROLE TO USER "<DEPLOY_USER>";<DEPLOY_USER> is the Snowflake user you are deploying as, which needs the role to create the service in stage 6. The name is quoted because a single sign-on account’s user name is usually an email address, and the unquoted form is a syntax error on the @. Quoting also makes the name case-sensitive, so copy it exactly as SHOW USERS reports it.
3. Allow Outbound Access to ALTR
Section titled “3. Allow Outbound Access to ALTR”Container network access is deny-by-default, so the service reaches ALTR only through a network rule and an external access integration. Reaching Snowflake itself needs no rule – that session stays inside the account.
USE ROLE ACCOUNTADMIN;
CREATE OR REPLACE NETWORK RULE SIS_APP.CORE.ALTR_DATAPLANE MODE = EGRESS TYPE = HOST_PORT VALUE_LIST = ( '<ALTR_ORGANIZATION_ID>.<DATA_PLANE_HOST>:443', '<CONFIG_BLOB_HOST>:443' );
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION ALTR_DATAPLANE_ACCESS ALLOWED_NETWORK_RULES = (SIS_APP.CORE.ALTR_DATAPLANE) ENABLED = TRUE;
GRANT USAGE ON INTEGRATION ALTR_DATAPLANE_ACCESS TO ROLE SIS_SERVICE_ROLE;Both entries are required, and each fails in its own way:
- The data plane host is your organization ID followed by the host of the Data Plane URL:
<ALTR_ORGANIZATION_ID>.<DATA_PLANE_HOST>, in lowercase. The scout never dials the bare host, so a rule naming the bare host creates successfully and then blocks every request the scout makes. - The configuration host is object storage, not the data plane. ALTR hands the scout a pre-signed URL for its task configuration, and the scout downloads that configuration from object storage with a separate connection. The host differs by ALTR environment, so ask ALTR Support for the value your organization needs. Snowflake permits one asterisk per entry, matching one subdomain level, so enter the value exactly as Support gives it rather than broadening it with another wildcard.
4. Store the ALTR Agent Key
Section titled “4. Store the ALTR Agent Key”The agent key is stored as a Snowflake secret, which the service reads at start-up. Paste the private key’s full PEM contents, including the header and footer lines, in place of <AGENT_PRIVATE_KEY_PEM>.
USE ROLE ACCOUNTADMIN;
CREATE SECRET IF NOT EXISTS SIS_APP.CORE.ALTR_AGENT_KEY TYPE = GENERIC_STRING SECRET_STRING = '<AGENT_PRIVATE_KEY_PEM>';
GRANT READ ON SECRET SIS_APP.CORE.ALTR_AGENT_KEY TO ROLE SIS_SERVICE_ROLE;The statement is CREATE SECRET IF NOT EXISTS so that re-running this stage can’t overwrite a key you have since rotated. To replace the stored key deliberately, see Agent Key Rotation.
5. Create the Compute Pool
Section titled “5. Create the Compute Pool”The compute pool provides the node the service runs on. The smallest instance family in the account is the right size – the scout’s work is dominated by reading Snowflake’s activity views, not by computation.
USE ROLE ACCOUNTADMIN;
CREATE COMPUTE POOL IF NOT EXISTS SIS_POOL MIN_NODES = 1 MAX_NODES = 1 INSTANCE_FAMILY = <INSTANCE_FAMILY> INITIALLY_SUSPENDED = TRUE AUTO_RESUME = TRUE AUTO_SUSPEND_SECS = 3600;
GRANT USAGE, MONITOR, OPERATE ON COMPUTE POOL SIS_POOL TO ROLE SIS_SERVICE_ROLE;The pool is created suspended and bills nothing until stage 6 creates the service on it. INSTANCE_FAMILY has to match both the account’s cloud provider and the image’s architecture – see Prerequisites.
Upload the Service Specification
Section titled “Upload the Service Specification”The service specification declares the image the service runs, the environment the scout reads its identity from, and how the agent key reaches the container. Save it as sis-service.yaml, substituting the 4 placeholders:
spec: containers: - name: scout image: /SIS_APP/CORE/IMAGES/sis:<IMAGE_TAG> env: SNOWFLAKE_AUTH_TYPE: OAUTH_AMBIENT SIS_ORG_ID: <ALTR_ORGANIZATION_ID> SIS_AGENT_ID: <AGENT_ID> SIS_HOSTNAME: <DATA_PLANE_HOST> ALTR_PRIVATE_KEY_PATH: /keys/secret_string LOG_FILE_LEVEL: "OFF" secrets: - snowflakeSecret: SIS_APP.CORE.ALTR_AGENT_KEY directoryPath: /keysSNOWFLAKE_AUTH_TYPE: OAUTH_AMBIENT is what selects the mounted-token authentication described above. SIS_ORG_ID, SIS_AGENT_ID, and SIS_HOSTNAME take the ALTR Organization ID, Agent ID, and Data Plane URL from the agent’s registration – the host of that URL, with no scheme and no port. A secret mounted by directoryPath lands as one file named after its key, which is why ALTR_PRIVATE_KEY_PATH points at /keys/secret_string. LOG_FILE_LEVEL: "OFF" turns off file logging, which the service has no volume to keep and which Snowflake wouldn’t surface anyway – the service’s log reaches you through SYSTEM$GET_SERVICE_LOGS.
Upload the file to the stage from stage 1:
snow sql -c <CONNECTION_NAME> -q \ "USE ROLE ACCOUNTADMIN; PUT file://sis-service.yaml @SIS_APP.CORE.SPECS AUTO_COMPRESS=FALSE OVERWRITE=TRUE;"6. Create the Service
Section titled “6. Create the Service”Create the service as SIS_SERVICE_ROLE, not as ACCOUNTADMIN. The scout runs as the role that owns the service, so creating it as ACCOUNTADMIN would give the container ACCOUNTADMIN and bypass the grants from stage 2.
USE ROLE SIS_SERVICE_ROLE;
CREATE SERVICE IF NOT EXISTS SIS_APP.CORE.SCOUT IN COMPUTE POOL SIS_POOL FROM @SIS_APP.CORE.SPECS SPECIFICATION_FILE = 'sis-service.yaml' EXTERNAL_ACCESS_INTEGRATIONS = (ALTR_DATAPLANE_ACCESS) QUERY_WAREHOUSE = SIS_WH MIN_INSTANCES = 1 MAX_INSTANCES = 1;Snowflake starts the compute pool and the service, and DESCRIBE SERVICE reports PENDING until the container is up. QUERY_WAREHOUSE isn’t optional: it is the only thing that gives the scout’s session a warehouse, and without it every read of Snowflake’s activity views fails with no active warehouse selected in the current session.
Running more than 1 instance is supported, but a second instance elects a leader with the first rather than sharing the work, so it stands by rather than adding throughput.
Deployment Verification
Section titled “Deployment Verification”Verification is read-only and needs no access to the container – the scout serves no HTTP endpoint, and its log reaches you through Snowflake. 09-verify.sql in the deployment assets runs the queries below in one pass:
snow sql -c <CONNECTION_NAME> -f 09-verify.sqlTo confirm the deployment:
-
Check that the service is running.
DESCRIBE SERVICE SIS_APP.CORE.SCOUTreportsRUNNINGin itsstatuscolumn, andSHOW SERVICE CONTAINERS IN SERVICE SIS_APP.CORE.SCOUTshows a container that isn’t restarting repeatedly. -
Read the service log, in order:
USE ROLE SIS_SERVICE_ROLE;SELECT SYSTEM$GET_SERVICE_LOGS('SIS_APP.CORE.SCOUT', 0, 'scout', 1000);Look for
Leadership acquiredfirst. It is an informational line, and it gates everything after it: the scout starts asking ALTR for its configuration only once it holds leadership, so no configuration line – success or failure – appears before it. After it, expect the configuration to load, then one task per scan task you created, then the first scan cycle. -
Check that scan queries are reaching the warehouse, which is independent of the log:
SELECT START_TIME, WAREHOUSE_NAME, ROLE_NAME, EXECUTION_STATUS, LEFT(QUERY_TEXT, 80) AS query_textFROM TABLE(SIS_APP.INFORMATION_SCHEMA.QUERY_HISTORY_BY_WAREHOUSE(WAREHOUSE_NAME => 'SIS_WH',END_TIME_RANGE_START => DATEADD('hour', -24, CURRENT_TIMESTAMP()),RESULT_LIMIT => 20))ORDER BY START_TIME DESC; -
Check that activity is arriving in ALTR, on the Agents page and in the Query Log.
Neither of these 2 failures reports itself as a fault:
42501orINSUFFICIENT_PRIVILEGESon the first scan means theIMPORTED PRIVILEGESgrant in stage 2 didn’t land.- A service that reaches
RUNNING, wins leadership, and then never loads a configuration points at the configuration host in stage 3.Network error downloading configuration versionin the log is that entry; the service starts cleanly either way, so absence is the only symptom.
Image Version Upgrade
Section titled “Image Version Upgrade”Upgrading re-points the running service at a new image tag, which CREATE SERVICE IF NOT EXISTS won’t do on a service that already exists. Suspend the service first:
snow sql -c <CONNECTION_NAME> -q \ "USE ROLE SIS_SERVICE_ROLE; ALTER SERVICE SIS_APP.CORE.SCOUT SUSPEND;"Bump SIS_IMAGE_SOURCE to the release you are upgrading to and SIS_IMAGE_VERSION to the tag it is pushed under inside the account, then run ./deploy.sh for the middle of the upgrade: it pushes the new tag and re-stages the specification, and the rest of the run is safe to repeat while the service is suspended. By hand, repeat the image copy with the new <VERSION> and <IMAGE_TAG>, and the specification upload with the new <IMAGE_TAG>. Then re-point the service and resume it:
snow sql -c <CONNECTION_NAME> -q \ "USE ROLE SIS_SERVICE_ROLE; ALTER SERVICE SIS_APP.CORE.SCOUT FROM @SIS_APP.CORE.SPECS SPECIFICATION_FILE = 'sis-service.yaml'; ALTER SERVICE SIS_APP.CORE.SCOUT RESUME;"The image copy is per account and per release, so each upgrade repeats it. The suspend and the re-point are the part deploy.sh can’t do for you.
Agent Key Rotation
Section titled “Agent Key Rotation”Rotating the agent key replaces the stored secret and restarts the service, which reads the secret at start-up. An agent accepts more than one registered key, so the old and new keys are both valid during the change and the scout keeps reporting throughout.
deploy.sh --rotate-secret does steps 2 through 6 below and deploys nothing else, waiting for each state change rather than assuming it. Point ALTR_PRIVATE_KEY_FILE at the new key before running it.
To rotate the agent key:
-
Register the new public key on the agent in ALTRNet, leaving the old key registered.
-
Replace the stored secret, then re-grant
READon it in the same session – replacing a Snowflake object drops the grants on it.USE ROLE ACCOUNTADMIN;CREATE OR REPLACE SECRET SIS_APP.CORE.ALTR_AGENT_KEYTYPE = GENERIC_STRINGSECRET_STRING = '<NEW_AGENT_PRIVATE_KEY_PEM>';GRANT READ ON SECRET SIS_APP.CORE.ALTR_AGENT_KEY TO ROLE SIS_SERVICE_ROLE; -
Suspend the service.
Terminal window snow sql -c <CONNECTION_NAME> -q \"USE ROLE SIS_SERVICE_ROLE;ALTER SERVICE SIS_APP.CORE.SCOUT SUSPEND;" -
Wait for
DESCRIBE SERVICE SIS_APP.CORE.SCOUTto reportSUSPENDEDin itsstatuscolumn. Resuming earlier hands the new key to a container still running on the old one. The secret is already replaced at this point, so the deployment stays down until the service resumes.Terminal window snow sql -c <CONNECTION_NAME> -q \"USE ROLE SIS_SERVICE_ROLE;DESCRIBE SERVICE SIS_APP.CORE.SCOUT;" -
Resume the service.
Terminal window snow sql -c <CONNECTION_NAME> -q \"USE ROLE SIS_SERVICE_ROLE;ALTER SERVICE SIS_APP.CORE.SCOUT RESUME;" -
Wait for the same
DESCRIBE SERVICEto reportRUNNING.RESUMEreturns before the container is back, and a service that hasn’t reachedRUNNINGafter about 3 minutes is most often one whose new key the agent rejected. Read the container log to check, using the query in09-verify.sql. -
Confirm the service is delivering on the new key before you go further – work through Deployment Verification. Reaching
RUNNINGproves only that the container started: the agent key authenticates to ALTR, not to Snowflake, so a key ALTR rejects leaves a container that runs without ever being accepted. -
Remove the old public key from the agent in ALTRNet.
Service Suspension
Section titled “Service Suspension”Suspending stops the compute pool’s charge without removing the deployment. Suspend the service before the pool – a pool won’t suspend while a service is scheduled on it.
USE ROLE SIS_SERVICE_ROLE;
ALTER SERVICE SIS_APP.CORE.SCOUT SUSPEND;ALTER COMPUTE POOL SIS_POOL SUSPEND;Resume in the reverse order, or resume the service alone – the pool resumes with it. Each scan task keeps its own position in the activity views, so a suspension delays audit records rather than losing them, as far back as Snowflake’s retention on those views.
The deployment bills in 2 places, with different shapes.
The compute pool bills for node uptime, not for query time. A long-lived service keeps its pool active, so AUTO_SUSPEND_SECS never fires and 1 node of the chosen instance family runs continuously. Check the credit rate for that family in Snowflake’s consumption table, and measure the pool’s actual usage after a full day:
SELECT START_TIME, COMPUTE_POOL_NAME, CREDITS_USEDFROM SNOWFLAKE.ACCOUNT_USAGE.SNOWPARK_CONTAINER_SERVICES_HISTORYWHERE COMPUTE_POOL_NAME = 'SIS_POOL' AND START_TIME >= DATEADD('day', -7, CURRENT_TIMESTAMP())ORDER BY START_TIME DESCLIMIT 50;The scan queries bill on SIS_WH, and warehouse resumes drive that cost. Snowflake bills a minimum of 60 seconds per resume and then per second, and each scan task runs at least 1 query per cycle.
The lever is the task’s schedule, set on the task in ALTRNet rather than on the warehouse – see Prerequisites for how to choose it.
Deployment Removal
Section titled “Deployment Removal”Removing the deployment drops every object the stages above create, in reverse order of dependency. 99-teardown.sql in the deployment assets is these statements, and deploy.sh prints the command for it when it finishes. The compute pool is the one that matters most: a pool left behind keeps billing a node continuously long after the service is gone.
USE ROLE ACCOUNTADMIN;
ALTER COMPUTE POOL IF EXISTS SIS_POOL STOP ALL;DROP SERVICE IF EXISTS SIS_APP.CORE.SCOUT;DROP COMPUTE POOL IF EXISTS SIS_POOL;DROP INTEGRATION IF EXISTS ALTR_DATAPLANE_ACCESS;DROP NETWORK RULE IF EXISTS SIS_APP.CORE.ALTR_DATAPLANE;DROP SECRET IF EXISTS SIS_APP.CORE.ALTR_AGENT_KEY;DROP STAGE IF EXISTS SIS_APP.CORE.SPECS;DROP IMAGE REPOSITORY IF EXISTS SIS_APP.CORE.IMAGES;DROP SCHEMA IF EXISTS SIS_APP.CORE;DROP DATABASE IF EXISTS SIS_APP;DROP WAREHOUSE IF EXISTS SIS_WH;DROP ROLE IF EXISTS SIS_SERVICE_ROLE;STOP ALL comes first because DROP COMPUTE POOL fails while any service still exists on the pool. Removing these objects doesn’t change anything in ALTR: remove the Snowflake Agent Repository’s registration there separately, or ALTR keeps serving task configuration to an agent that no longer exists.