Gérer les secrets et configurer votre application Streamlit

Les applications Streamlit ont souvent besoin d’accéder à des informations sensibles, telles que des clés d’API, des mots de passe et d’autres identifiants de connexion. La manière dont vous gérez les secrets dans votre application Streamlit dépend de l’environnement d’exécution que vous utilisez. Streamlit in Snowflake fournit des mécanismes sécurisés et intégrés pour accéder aux secrets dans les environnements d’exécution des entrepôts et des conteneurs. Pour la configuration Streamlit, chaque exécution présente également des restrictions différentes.

Dans la bibliothèque Streamlit, les applications utilisent un répertoire .streamlit/ pour stocker la configuration et les secrets :

  • .streamlit/config.toml : Personnalise les paramètres de l’application, tels que le thème, la disposition et le comportement du serveur.

  • .streamlit/secrets.toml : Stocke des informations sensibles, telles que des clés d’API et des identifiants de connexion (dans le développement local).

Streamlit in Snowflake prend en charge ces fichiers avec certaines limitations en fonction de votre environnement d’exécution. Le tableau suivant résume la prise en charge de ces fichiers dans les exécutions d’entrepôts et de conteneurs :

Fonctionnalité

Exécution d’entrepôts

Exécution de conteneurs

Prise en charge de config.toml

Sous-ensemble limité d’options de configuration

Sous-ensemble plus large d’options de configuration

Prise en charge de secrets.toml

Non pris en charge

Pris en charge, mais uniquement recommandé pour les variables d’environnement non secrètes

Pour secrets.toml, Streamlit in Snowflake fournit un système de gestion des secrets intégré plus sécurisé, qui est recommandé pour la gestion des informations sensibles. Les sections suivantes décrivent comment utiliser les secrets Snowflake dans vos applications.

Gestion de votre connexion à Snowflake

Pour gérer votre connexion à Snowflake, vous pouvez utiliser une st.connection("snowflake"). Celle-ci vous permet de vous connecter à Snowflake à partir de votre environnement de développement local et de votre application déployée.

import streamlit as st

conn = st.connection("snowflake")
session = conn.session()

session.sql("SELECT 1").collect()
Copy

Dans les exécutions d’entrepôts, vous pouvez également utiliser la fonction get_active_session() de Snowpark pour accéder à la session active.

import streamlit as st
from snowflake.snowpark.context import get_active_session

# ONLY IN WAREHOUSE RUNTIMES
session = get_active_session()
session.sql("SELECT 1").collect()
Copy

Important

get_active_session() n’est pas sécurisé pour les threads et ne peut pas être utilisé dans les exécutions de conteneurs.

Secrets dans les exécutions de conteneurs

Les exécutions de conteneurs n’ont pas accès au module _snowflake, car ils fonctionnent en dehors de l’environnement de la procédure stockée. Pour accéder aux secrets dans une exécution de conteneur, vous devez créer des fonctions SQL qui utilisent le module _snowflake, puis appeler ces fonctions depuis votre application Streamlit. Pour les appels d’API Cortex, vous devez utiliser des requests.

Si vous mettez à niveau une ancienne application Streamlit vers une exécution de conteneur, les fonctions _snowflake suivantes doivent être remplacées par des procédures stockées. Ceci est décrit dans la section suivante.

  • get_generic_secret_string

  • get_oauth_access_token

  • get_username_password

  • get_cloud_provider_token

  • get_secret_type

En outre, la fonction _snowflake suivante doit être remplacée par un appel d’API manuel, authentifié avec un jeton de session. Ceci est décrit dans la section ultérieure Appel d’un Agent Cortex dans une exécution de conteneur.

  • send_snow_api_request

Accéder à un secret dans une exécution de conteneur

Pour accéder à un secret dans une exécution de conteneur, procédez comme suit :

  1. Créez un secret dans votre compte Snowflake. Voir CREATE SECRET.

    CREATE OR REPLACE SECRET my_secret
      TYPE = GENERIC_STRING
      SECRET_STRING = 'my_secret_value';
    
    Copy
  2. Créez une fonction pour accéder à votre secret. Voir API Python pour l’accès aux secrets.

    CREATE OR REPLACE FUNCTION get_my_secret()
      RETURNS STRING
      LANGUAGE PYTHON
      RUNTIME_VERSION = 3.12
      HANDLER = 'get_my_secret'
      EXTERNAL_ACCESS_INTEGRATIONS = (my_eai)
      SECRETS = ('my_secret' = my_secret)
      AS
    $$
    import _snowflake
    
    def get_my_secret():
      return _snowflake.get_generic_secret_string('my_secret')
    $$;
    
    Copy
  3. Créez votre application Streamlit avec l’exécution de conteneur :

    CREATE STREAMLIT my_container_app
      FROM '@my_stage/app_folder'
      MAIN_FILE = 'streamlit_app.py'
      RUNTIME_NAME = 'SYSTEM$ST_CONTAINER_RUNTIME_PY3_11'
      COMPUTE_POOL = my_compute_pool
      QUERY_WAREHOUSE = my_warehouse
      EXTERNAL_ACCESS_INTEGRATIONS = (my_eai);
    
    Copy
  4. Dans le code de votre application Streamlit, appelez la fonction SQL pour récupérer le secret :

    import streamlit as st
    
    # Get the Snowflake connection
    conn = st.connection("snowflake")
    session = conn.session()
    
    # Call the function to retrieve the secret
    secret = session.sql("SELECT get_my_secret()").collect()[0][0]
    
    Copy

Utiliser .streamlit/secrets.toml pour les variables d’environnement non secrètes

Même si vous pouvez techniquement ajouter un fichier .streamlit/secrets.toml au répertoire source de votre application, ceci n’est pas recommandé pour stocker des secrets réels. Le fichier secrets.toml est stocké sous forme de texte brut dans vos fichiers en zone de préparation, ce qui ne constitue pas une bonne pratique en matière de sécurité.

Cependant, secrets.toml peut être utile pour stocker des valeurs de configuration non sensibles ou des paramètres spécifiques à l’environnement auxquels vous souhaitez accéder via st.secrets dans votre code ou qu’une dépendance requiert comme variable d’environnement :

# .streamlit/secrets.toml
# ONLY USE FOR NON-SECRET CONFIGURATION VALUES
app_name = "My Streamlit App"
api_endpoint = "https://api.example.com"
max_results = 100
Copy

Vous pouvez ensuite accéder à ces valeurs dans votre application via st.secrets ou en tant que variables d’environnement :

import streamlit as st
import os

app_name = st.secrets["app_name"]
API_ENDPOINT = os.getenv("API_ENDPOINT")
Copy

Pour les secrets réels comme les clés d’API, les mots de passe et les jetons, utilisez toujours le système de gestion des secrets intégré de Snowflake, comme décrit dans la section précédente.

Appel d’un Agent Cortex dans une exécution de conteneur

Pour appeler un Agent Cortex dans une application d’exécution de conteneurs, lisez le jeton de session à partir du conteneur Snowpark Container Services sous-jacent, puis utilisez la bibliothèque requests. Il s’agit du remplacement recommandé pour _snowflake.send_snow_api_request().

import requests
import json
import os

SNOWFLAKE_HOST = os.getenv("SNOWFLAKE_HOST")
SNOWFLAKE_ACCOUNT = os.getenv("SNOWFLAKE_ACCOUNT")
ANALYST_ENDPOINT = "/api/v2/cortex/analyst/message"
URL = "https://" + SNOWFLAKE_HOST + ANALYST_ENDPOINT

def get_token() -> str:
    """Read the oauth token embedded into SPCS container"""
    return open("/snowflake/session/token", "r").read()

def send_request(semantic_model_file, prompt):
    """Sends the prompt using the semantic model file """
    headers = {
        "Content-Type": "application/json",
        "accept": "application/json",
        "Authorization": f"Bearer {get_token()}",
        "X-Snowflake-Authorization-Token-Type": "OAUTH"
    }
    request_body = {
        "messages": [
            {
                "role": "user",
                "content": [{"type": "text", "text": prompt}],
            }
        ],
        "semantic_model_file": semantic_model_file,
    }
    return requests.post(URL, headers=headers, data=json.dumps(request_body))
Copy

Secrets dans les exécutions d’entrepôts

Dans les exécutions d’entrepôts, vous pouvez utiliser le module _snowflake pour accéder aux secrets directement dans le code de votre application Streamlit. Les exécutions d’entrepôts héritent de l’accès au module _snowflake à partir de procédures stockées, ce qui vous permet de récupérer les secrets qui sont référencés dans l’objet Streamlit.

Pour utiliser des secrets dans une exécution d’entrepôts, procédez comme suit :

  1. Créez un objet secret dans Snowflake. Pour plus d’informations, voir CREATE SECRET.

    CREATE OR REPLACE SECRET my_secret
      TYPE = GENERIC_STRING
      SECRET_STRING = 'my_secret_value';
    
    Copy
  2. Créez une intégration d’accès externe et attribuez-lui le secret.

    CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION my_eai
      ALLOWED_AUTHENTICATION_SECRETS = (my_secret)
      ENABLED = TRUE;
    
    Copy
  3. Référencez le secret dans votre objet Streamlit à l’aide du paramètre SECRETS :

    ALTER STREAMLIT my_warehouse_app
      SET EXTERNAL_ACCESS_INTEGRATIONS = (my_eai)
      SECRETS = ('my_secret_key' = my_secret);
    
    Copy

    Vous devez attribuer à l’objet Streamlit à la fois l’intégration d’accès externe et le secret. Vous ne pouvez pas attribuer un secret à un objet Streamlit par lui-même.

  4. Dans le code de votre application Streamlit, importez le module _snowflake et récupérez le secret :

    import streamlit as st
    import _snowflake
    
    # Retrieve an API key from a generic string secret
    my_secret = _snowflake.get_generic_secret_string('my_secret_key')
    
    Copy

Pour plus d’informations sur l’accès aux secrets avec le module _snowflake, consultez API Python pour l’accès aux secrets.

Configuration de Streamlit

Les applications Streamlit peuvent inclure un fichier de configuration (.streamlit/config.toml). Ce fichier vous permet de personnaliser divers aspects de votre application, tels que le thème, la disposition et le comportement. Le fichier de configuration est écrit au format TOML. Pour plus d’informations sur les options de configuration disponibles, consultez la documentation Streamlit sur config.toml.

La prise en charge des options de configuration varie selon l’environnement d’exécution. Les exécutions de conteneurs offrent généralement une prise en charge plus large des options de configuration que les exécutions d’entrepôts, en particulier pour le service statique. Le tableau suivant montre les sections de configuration prises en charge dans les exécutions d’entrepôts et de conteneurs :

Section de configuration

Exécution d’entrepôts

Exécution de conteneurs

[global]

Non pris en charge

Prise en charge limitée (disableWidgetStateDuplicationWarning)

[logger]

Non pris en charge

Non pris en charge

[client]

Non pris en charge

Prise en charge limitée (showErrorDetails, showSidebarNavigation)

[runner]

Non pris en charge

Pris en charge

[server]

Non pris en charge

Non pris en charge

[browser]

Non pris en charge

Non pris en charge

[mapbox]

Non pris en charge

Prise en charge (obsolète, utilisez des variables d’environnement à la place)

[theme]

Pris en charge

Pris en charge

[theme.sidebar]

Pris en charge

Pris en charge

[secrets]

Non pris en charge

Prise en charge (mais uniquement recommandée pour les variables d’environnement non secrètes)

[snowflake.sleep]

Pris en charge

Non applicable

Pour plus d’informations sur l’utilisation de la section [snowflake.sleep] pour configurer les minuteurs de mise en veille dans les exécutions d’entrepôts, consultez Minuterie de mise en veille personnalisée pour une application Streamlit.

La structure des répertoires suivante montre un exemple d‘application Streamlit avec un fichier de configuration :

source_directory/
├── .streamlit/
│   └── config.toml
├── pyproject.toml
├── streamlit_app.py
└── uv.lock
Copy