Lutril needs your account identifier and a programmatic access token to list, create, disable and grant roles to Snowflake users through the REST API. Every statement below runs in a Snowsight worksheet and takes about five minutes end to end. Snowflake scopes roles and users per account, so a token only ever reaches the one account it was made in: run this once per environment you want governed.
SECURITYADMIN, granted to the service user and set as the token's ROLE_RESTRICTION
A network policy covering the service user (Snowflake requires one before a service token works)
REST API v2: GET /users, GET /roles, POST /users, PUT /users/{name}, POST /users/{name}/grants
Setup steps
1
Open a Snowsight worksheet on the account you want Lutril to govern. You need ACCOUNTADMIN for the grant in step 3; everything else needs USERADMIN or higher.
Create the service user. TYPE = SERVICE is the important part: it is a user that cannot log in interactively and has no password or MFA, so the token from step 4 is its only credential.
SQL
USE ROLE USERADMIN;
CREATE USER IF NOT EXISTS LUTRIL_SVC
TYPE = SERVICE
DEFAULT_ROLE = SECURITYADMIN
COMMENT = 'Lutril access governance service account';
LUTRIL_SVC is only a name. Use whatever your naming convention wants, and keep it consistent across environments so the audit trail reads the same everywhere.
3
Grant it SECURITYADMIN. Lutril needs to grant and revoke roles on users it did not create, which requires the MANAGE GRANTS privilege that SECURITYADMIN carries. USERADMIN on its own can create users but cannot grant roles it does not own.
SQL
USE ROLE ACCOUNTADMIN;
GRANT ROLE SECURITYADMIN TO USER LUTRIL_SVC;
4
Attach a network policy. Snowflake will refuse to create or use a token on a service user that no network policy covers, so this is not optional. Skip the CREATE if you already have an account-level policy.
SQL
USE ROLE SECURITYADMIN;
CREATE NETWORK POLICY IF NOT EXISTS LUTRIL_ACCESS
ALLOWED_IP_LIST = ('203.0.113.10/32')
COMMENT = 'Egress addresses Lutril calls Snowflake from';
ALTER USER LUTRIL_SVC SET NETWORK_POLICY = LUTRIL_ACCESS;
203.0.113.10 is a placeholder from the range reserved for documentation. Replace it with Lutril's egress addresses before you run this, or the token will authenticate from nowhere. Ask us and we will send you the current list.Network policies guide
5
Generate the token. ROLE_RESTRICTION is mandatory for a service user and it caps what the token can ever do, even if the user is granted more later. Expiry defaults to 15 days; 365 is the maximum Snowflake allows.
SQL
USE ROLE ACCOUNTADMIN;
ALTER USER IF EXISTS LUTRIL_SVC
ADD PROGRAMMATIC ACCESS TOKEN LUTRIL_PAT
ROLE_RESTRICTION = 'SECURITYADMIN'
DAYS_TO_EXPIRY = 365
COMMENT = 'Lutril REST API access';
The statement returns the secret once, in its result. Copy it before you close the worksheet: Snowflake will not show it again, and the only recovery is to add a second token.
6
Read your account identifier. Lutril builds the API host from it, so it has to be the orgname-account_name form and not the legacy locator.
SQL
SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME() AS account_identifier;
Optional, and worth the thirty seconds: confirm the token can do the exact call Lutril makes first. A 200 with a JSON array means you are done; a 401 means the token or its role restriction is wrong, and a timeout means the network policy does not cover the caller.
If your account name contains an underscore you can swap it for a hyphen in the hostname; Snowflake accepts both forms.
8
In Lutril, connect Snowflake and paste the account identifier and the token. Set a calendar reminder to rotate before the expiry you chose: when a token lapses, listing and provisioning stop and any access review covering this account goes stale.