Watch a demoFree trial
Blog

Comment assainir les données de l'environnement de prévisualisation

gdprdonnéesscripts d'activitél'automatisation
Partager
Cet article est également disponible en Anglais.

Être conforme au RGPD dans tous vos projets est un défi quotidien, en particulier si vous gérez des données utilisateur sensibles sur vos projets. Upsun adopte une approche RGPD everywhere avec des niveaux élevés de sécurité et de conformité intégrés en standard, mais il existe des moyens de sécuriser davantage vos données sur notre PaaS lorsqu'il s'agit d'environnements de prévisualisation.

Chaque fois que vous créez une nouvelle branche Git sur un projet sur Upsun, l'environnement correspondant hérite des données (actifs et base de données) de son parent. Cela signifie que des données potentiellement sensibles de votre site web de production peuvent être exposées à l'environnement de prévisualisation.

Alors, comment s'y retrouver et s'assurer que votre application reste conforme ? Deux mots : assainissement des données. Il s'agit de l'effacement délibéré et permanent de données sensibles d'un dispositif de stockage, ce qui rend les données irrécupérables. Dans cet article, je partagerai les méthodes d'assainissement des données que vous pouvez mettre en œuvre pour les environnements de prévisualisation afin de garantir que vos données restent en sécurité à chaque étape du développement.

Quelques ressources nécessaires avant de commencer

Nous avons quelques prérequis pour nous assurer que vous pouvez suivre les solutions et les étapes détaillées dans cet article, veuillez vous assurer que vous avez installé les éléments suivants :

Méthodes d'assainissement des données de l'application

Pour les besoins de cet article, nous allons nous concentrer sur l'assainissement des données de l'environnement de prévisualisation sur Symfony, cependant, les méthodes détaillées s'appliquent à tous les frameworks.

Si vous voulez plus de détails sur la façon de mettre en place des applications Symfony Demo sur Upsun, jetez un coup d'oeil à notre guide Up(sun) and running with Symfony Demo.

Tout au long de l'article, nous allons passer en revue les différentes méthodes disponibles pour assainir les données de l'environnement Symfony sur Upsun, 5 méthodes pour être exact que vous pouvez évaluer et choisir la meilleure pour vous. Cependant, assurez-vous que vous avez terminé l'étape de création d'une commande avant de procéder à une méthode.

Si vous connaissez déjà la méthode que vous préférez utiliser, cliquez sur le titre correspondant ci-dessous et nous vous y emmènerons directement :

Tout d'abord, créez une commande pour assainir vos données

Remarque: si vous hébergez un stack autre que Symfony, veuillez adapter la commande pour assainir votre base de données dans votre stack et la pousser vers votre branche de production. C'est la seule étape spécifique à Symfony dans cet article.

Pour exécuter l'une des cinq méthodes d'assainissement des données listées ci-dessus, nous avons besoin d'un appelable pour assainir nos environnements. Il y a deux façons possibles de le faire :

  1. Utiliser un script SQL pour mettre à jour ou falsifier toutes les données sensibles.
  2. En utilisant une commande Symfony pour le faire, peut-être en utilisant le bundle fakerPHP.

Puisque nous utilisons une application Symfony Demo, nous utiliserons la seconde option. Faites ce qui suit, à partir de la branche main de Git :

symfony composer require --dev fakerphp/faker
git add composer.json composer.lock && git commit -m "composer require --dev fakerphp bundle" 

Ensuite, ouvrez votre code dans votre IDE préféré et créez une nouvelle commande Symfony, dans un fichier SRC/command/SanitizeDataCommand.php, avec ce qui suit :

<?php
/* src/Command/SanitizeDataCommand.php */

namespace App\Command;

use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Faker;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(
   name: 'app:sanitize-data',
   description: 'Sanitize user data (username and email).',
   aliases: ['app:sanitize']
)]
class SanitizeDataCommand extends Command
{
   private SymfonyStyle $io;

   public function __construct(private UserRepository $userRepository, private EntityManagerInterface $entityManager)
   {
       parent::__construct();
   }

   protected function configure()
   {
       $this
           ->setDescription('This command allows you to sanitize user data (username and email).');
   }

   protected function initialize(InputInterface $input, OutputInterface $output): void
   {
       $this->io = new SymfonyStyle($input, $output);
   }

   protected function execute(InputInterface $input, OutputInterface $output): int
   {
       $users = $this->userRepository->findAll();
       $this->io->progressStart(count($users));

       $this->entityManager->getConnection()->beginTransaction(); // suspend auto-commit
       try {
           /** @var User $user */
           foreach ($users as $user) {
               $this->io->progressAdvance();
               // initialize faker
               $faker = Faker\Factory::create();

               $this->io->text('faking user '.$user->getUsername());
               // fake user info
               $user->setUsername(uniqid($faker->userName()));
               $user->setEmail($faker->email());
               // please adapt to your needs
           }   

           $this->entityManager->flush();
           $this->entityManager->getConnection()->commit();
           $this->io->progressFinish();
       } catch (\Exception $e) {
           $this->entityManager->getConnection()->rollBack();
           throw $e;
       }

       return Command::SUCCESS;
   }
}

Cette commande app:sanitize-data utilise le UserRepository et falsifie le nom d'utilisateur et l'email de l'entité par défaut User Symfony. Veuillez l'adapter à vos besoins. Ensuite, ajoutez votre code à la branche main:

git add src/Command/SanitizeDataCommand.php && git commit -m "sanitize data command" 
symfony deploy

1) Assainir manuellement vos données

Maintenant que votre code source contient une commande Symfony pour assainir vos données, nous allons l'utiliser manuellement dans un nouvel environnement de prévisualisation. En commençant par créer une nouvelle branche staging et en attendant que le processus se termine, comme suit :

symfony branch staging --type=staging

Ensuite, exécutez votre commande Symfony nouvellement créée sur votre environnement Upsun staging, comme indiqué ci-dessous :

symfony ssh php bin/console -e dev app:sanitize-data

Et voilà, les données de votre environnement de prévisualisation sont assainies !

2) Utiliser l'héritage d'environnement

Dans cette section, nous allons créer un environnement de prévisualisation, assainir ses données, et ensuite faire en sorte que tous les nouveaux environnements héritent de cet environnement de prévisualisation.

Comme mentionné au début de cet article, chaque fois que vous créez une nouvelle branche Git sur Upsun, l'environnement créé héritera des données de l'environnement parent. Cependant, il est possible de modifier l'héritage des données par défaut et de le configurer plus tard pour synchroniser les données d'un nouveau parent l'environnement de prévisualisation que nous allons créer.

Le CLI Symfony offre la possibilité de créer une branche sans parent, en utilisant l'option --no-clone-parent, puis en définissant le parent à staging (a.k.a prévisualisation), ce qui garantit que les nouvelles branches héritent des données de l'environnement de prévisualisation. Suivez les instructions de l'étape 1 pour plus de détails sur la façon d'assainir manuellement les données de l'environnement de prévisualisation afin de garantir que toutes les branches futures héritent de données assainies et conformes au RGPD.

symfony checkout main
symfony branch dev --no-clone-parent
symfony env:info -e dev parent staging
symfony sync -e dev data

Et voilà, votre nouvel environnement de dev est maintenant créé avec les données nettoyées de votre environnement de prévisualisation.

3) Utiliser un hook

Plutôt que de s'appuyer sur l'héritage, il peut être souhaitable d'assainir certaines données à chaque déploiement. Dans ce cas, nous pouvons déplacer notre appel de script dans la section " hooks" de la configuration.

Le type de hook que vous choisissez vous appartient deploy ou post_deploy, mais voici quelques points à garder à l'esprit :

  • Un scripts à longue durée d'exécution dans le hook deploy devra prolonger le temps de déploiement d'une application.
  • Un script de longue durée dans le hook post_deploy pourrait rendre momentanément publiques des données non conformes/critiques pendant que l'assainissement est en cours.
  • Redéploiements ; si l'assainissement est quelque chose que vous aimeriez pouvoir déclencher manuellement avec un redéploiement, l'assainissement aura lieu à chaque redéploiement seulement s'il est placé dans le hook post_deploy.

Pour exécuter une commande Symfony pendant le hook post_deploy, ajoutez ce qui suit dans votre .upsun/config.yaml:

applications:
  app:
    hooks:
      build: ...
      deploy: ...

      post_deploy: |
        if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ]; then
          # L'assainissement de la base de données devrait avoir lieu ici (puisque ce n'est pas la production)
          php bin/console -e dev app:sanitize-data
        fi

Poussez ensuite votre code sur la branche main:

git checkout main && git add .upsun/config.yaml && git commit -m "add sanitize data command to post_deploy hook" 
symfony deploy

4) Utiliser des opérations d'exécution et des scripts d'activité

Il y a une autre option qui vous permet de créer un déclencheur personnalisé qui est exécuté en réponse à certaines activités qui ont lieu sur le projet. Par exemple, lors de la synchronisation d'un environnement avec son parent, nous pourrions synchroniser les données non anonymisées du parent (par exemple, si la synchronisation se fait à partir de l'environnement de production).

Les deux composants qui permettront de réaliser cette opération sont les suivants :

  • Une opération d'exécution: elle vous permettra de déclencher des commandes ou des scripts uniques sur votre projet. Similaires aux crons, ils s'exécutent dans le conteneur d'application mais pas selon un horaire précis.
  • Un script d'activité: un morceau de code JavaScript qui sera exécuté en réponse à certaines activités se déroulant au niveau du projet, de l'environnement ou même de l'organisation.

Nous allons donc ajouter une intégration (script d'activité) qui répond à certains événements pour exécuter une opération d'exécution afin d'assainir les données à la volée, voir l'ajout d'une intégration d' un script d'activité ci-dessous.

Remarque: si vous avez défini un hook post_deploy à l'étape précédente, veuillez le commenter car il ne sera plus nécessaire après l'utilisation de cette opération d'exécution.

Comment créer une opération d'exécution

Pour configurer une opération d'exécution, nous devons ajouter une nouvelle clé YAML de premier niveau dans notre fichier .upsun/config.yaml avec ce qui suit :

applications:
  app: 
    operations:
      sanitize:
        role: admin
        commands:
          start: |
            if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ]; then
              # L'assainissement de la base de données devrait avoir lieu ici (puisque ce n'est pas la production)
              php bin/console -e dev app:sanitize-data
            fi

Poussez ensuite votre fichier vers la branche main et déployez-le.

git checkout main 
git add .upsun/config.yaml && git commit -m "add runtime operation to sanitize data"
symfony deploy

Et si vous voulez tester cette opération d'exécution manuellement, vous pouvez utiliser ce qui suit :

symfony operation:run sanitize --app=app

Comment créer un script d'activité

Upsun supporte les scripts personnalisés qui peuvent être déclenchés en réponse à n'importe quelle activité. Ce script est exécuté en dehors du contexte de l'environnement et nous devons donc recréer ce contexte pour que le script d'activité soit exécuté avec les droits nécessaires. Pour ce faire, créez un nouveau fichier src/runtime/sanitize.js avec ce qui suit :

// src/runtime/sanitize.js
let app_container = "app";
let runtime_operation_name = "sanitize";

if (!variables.api_token) {
    console.log("Variable API Token is not defined!");
    console.log("Please define an environment variable with your API Token using command: ");
    console.log("upsun project:curl /integrations/<INTEGRATION_ID>/variables -X POST -d '{\"name\": \"api_token\", \"value\": \"<API_TOKEN>\", \"is_sensitive\": true, \"is_json\": false}' ");
} else {
    console.log("OAuth2 API Token defined");
    let resp = fetch('https://auth.api.platform.sh/oauth2/token', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: "client_id=platform-api-user&grant_type=api_token&api_token=" + variables.api_token
    });

    if (!resp.ok) {
        console.log("Failed to get an OAuth2 token, status code was " + resp.status);
    } else {
        console.log("OAuth2 API TOKEN ok");
    }

    let access_token = resp.json().access_token;

    // get current branch from activity object
    let branch;
    switch (activity.type) {
        case 'environment.synchronize':
            branch = activity.parameters.into;
            break;
        case 'environment.branch':
        case 'environment.activate':
            branch = activity.parameters.environment;
            break;
    }

    // run runtime operation runtime_operation_name on current/targeted environment
    resp = fetch("https://api.upsun.com/api/projects/" + activity.project + "/environments/" + branch + "/deployments/current/operations",
        {
            headers: {
                "Authorization": "Bearer " + access_token
            },
            method: "POST",
            body: JSON.stringify({"service": app_container, "operation": runtime_operation_name}),
        });

    if (!resp.ok) {
        console.log("Failed to invoke the runtime operation, status code was " + resp.status);
    } else {
        console.log(runtime_operation_name + " launched");
    }
}

Ce script d'activité utilise un jeton API, en tant que variable d'environnement, pour se connecter à l'environnement actuel et exécuter l'opération d'exécution définie précédemment à l'aide de l'API Upsun. Nous devons définir cette variable d'environnement pour l'intégration de notre script d'activité, et ajouter plus tard une variable d'environnement API Token.

Ensuite, poussez votre fichier sur la branche principale et déployez-le, comme suit :

symfony checkout main 
git add src/runtime/sanitize.js
git commit -m "add activity script"
symfony deploy

Ajouter une intégration d'un script d'activité

Trois événements Upsun doivent déclencher cette opération d'exécution :

  • Lors de la création d'une nouvelle branche (environment.branch),
  • Lors de la synchronisation des données entre les environnements (environment.synchronize),
  • Lors de l'activation d'un environnement de prévisualisation (environment.activate) .

Pour mettre en place ces déclencheurs, utilisez cette commande dans votre terminal pour ajouter une intégration de script d'activité.

symfony integration:add --type script --file ./src/runtime/sanitize.js --events environment.branch,environment.synchronize,environment.activate --states complete --environments \*

Remarque: une liste complète des événements possibles est disponible dans la définition du type de script d'activité. N'importe lequel de ces types de scripts d'activité peut être ajouté en tant que liste d'événements dans l'option --events=event1,event2,....

Ajouter une variable d'environnement API Token

Tout d'abord, obtenez l'ID de l'intégration précédente en utilisant la commande suivante :

symfony integration:list

Ensuite, créez un nouveau Token API depuis la Console, gardez la valeur en main, et remplacez-la dans cette commande du terminal :

symfony project:curl /integrations/<INTEGRATION_ID>/variables -X POST -d '{"name" : "api_token", "value" : "<API_TOKEN>", "is_sensitive" : true, "is_json" : false}'

Remarque: remplacez <INTEGRATION_ID> et <API_TOKEN> par les valeurs correspondantes créées précédemment.

Vous pouvez vérifier que la variable a été créée avec cette commande :

symfony project:curl /integrations/<INTEGRATION_ID>/variables

Il est temps de tester

Pour tester si tout a fonctionné, dans la Console ou avec le CLI, déclenchez la création d'une nouvelle branche à partir de main, déclenchez une synchronisation, désactivez et réactivez votre environnement de prévisualisation, et vous devriez alors voir deux activités :

  • Activité déclenchée
  • Une activité d'opération en cours d'exécution

Vous rencontrez un problème ? Déboguez-le

Si vous rencontrez un problème et que vous souhaitez déboguer l'intégration du script d'activité, vous devez utiliser la commande suivante :

symfony integration:activity:log <INTEGRATION_ID>

Lorsque vous ajoutez l'intégration de votre script d'activité, le script correspondant est ajouté en mémoire du côté d'Upsun. Cela signifie qu'à chaque fois que vous mettez à jour votre script, vous devez mettre à jour la version en cache du fichier, en utilisant la commande suivante : symfony integration:update <INTEGRATION_ID> :

symfony integration:update <INTEGRATION_ID> --file ./src/runtime/sanitize.js

Remarque: bien entendu, pour maintenir votre code source à jour, vous devez livrer ce fichier :

git add src/runtime/sanitize.js
git commit -m "add activity script"
symfony deploy # optional

5) Comment utiliser des scripts shell pour assainir les environnements de développement

Il est possible d'utiliser un script shell pour automatiser l'assainissement des données de tous vos environnements, à l'exception de la production, pour tous vos projets au sein d'une organisation apprenez-en plus sur les organisations ici. Pour utiliser ce script shell, veuillez vous assurer que toutes vos sources d'environnement de tous vos projets au sein de votre organisation contiennent la commande Symfony pour assainir les données, avant de suivre les étapes suivantes.

La première étape consiste à créer un fichier nommé fleet_sanitizer.sh avec le code suivant :

if [ -n "$ZSH_VERSION" ]; then emulate -L ksh; fi
######################################################
# fleet sanitization demo script, using the CLI.
# 
# Enables the following workflow on a given project and sanitize preview environments (staging, new-feature and auto-updates environment:
# .
# └── main
#     ├── staging
#     |   └── new-feature
#     └── auto-updates
#
# Usage
# 1. source this script: `. fleet_sanitizer.sh` or `source fleet_sanitizer.sh` depending of your local machine
# 2. define ORGANIZATION var: ORGANIZATION=<organizationIdentifier>
# 3. run `sanitize_organization_data $ORGANIZATION`
######################################################

# Utility functions.

# list_org_projects: Print list of projects operation will be applied to before starting.
#   $1: Organization, as it appears in console.upsun.com.
list_org_projects() {
  symfony project:list -o $1 --columns="ID, Title"
}

# get_org_projects: Retrieve an array of project IDs for a given organization.
#   Note: Makes array variable PROJECTS available to subsequent scripts.
#   $1: Organization, as it appears in console.upsun.com.
get_org_projects() {
  PROJECTS_LIST=$(symfony project:list -o $1 --pipe)
  PROJECTS=($PROJECTS_LIST)
}

# get_project_envs: Retrieve an array of envs IDs for a project.
#   Note: Makes array variable ENVS available to subsequent scripts.
#   $1: ProjectId, as it appears in console.upsun.com.
get_project_envs() {
  ENV_LIST=$(symfony environment:list -p $1 --pipe)
  ENVS=($ENV_LIST)
}

# list_project_envs: Print list of envs operation will be applied to before starting.
#   $1: ProjectId, as it appears in console.upsun.com.
list_project_envs() {
  symfony environment:list -p $1
}

# add_env_var: Add environment level environment variable.
#   $1: Variable name.
#   $2: Variable value.
#   $3: Target project ID.
#   $4: Target environment ID.
add_env_var() {
  VAR_STATUS=$(symfony project:curl -p $3 /environments/$4/variables/env:$1 | jq '.status')
  if [ "$VAR_STATUS" != "null" ]; then
    symfony variable:create --name $1 --value "$2" --prefix env: --project $3 --environment $4 --level environment --json false --sensitive false --visible-build true --visible-runtime true --enabled true --inheritable true -q
  else
    printf "\nVariable $1 already exists. Skipping."
  fi
}

# Main functions.
sanitize_organization_data() {
  list_org_projects $1
  get_org_projects $1
  for PROJECT in "${PROJECTS[@]}"; do
    printf "\n### Project $PROJECT."
    # get environments list
    list_project_envs $PROJECT
    get_project_envs $PROJECT
    for ENVIRONMENT in "${ENVS[@]}"; do
      unset -f ENV_CHECK
      ENV_CHECK=$(symfony project:curl -p $PROJECT /environments/$ENVIRONMENT | jq -r '.status')
      unset -f ENV_TYPE
      ENV_TYPE=$(symfony project:curl -p $PROJECT /environments/$ENVIRONMENT | jq -r '.type')

      if [ "$ENV_CHECK" = active -a "$ENV_TYPE" != production ]; then
        unset -f DATA_SANITIZED
        DATA_SANITIZED=$(symfony variable:get -p $PROJECT -e $ENVIRONMENT env:DATA_SANITIZED --property=value)
        if [ "$DATA_SANITIZED" != true ]; then
          printf "\nEnvironment $ENVIRONMENT exists and is not sanitized yet. Sanitizing data."
          printf "\n"
          # do sanitization here
          symfony ssh -p $PROJECT -e $ENVIRONMENT -- php bin/console app:sanitize-data
          printf "\nSanitizing data is finished, redeploying"
          add_env_var DATA_SANITIZED true $PROJECT $ENVIRONMENT
        else
          printf "\nEnvironment $ENVIRONMENT exists and does not need to be sanitized. skipping."
        fi
      elif [ "$ENVIRONMENT" == main ]; then
        printf "\nEnvironment $ENVIRONMENT is production one, skipping."
      else
        printf "\nEnvironment $ENVIRONMENT is not active $ENV_CHECK, skipping."
      fi
    done
  done
}

Remarque: dans ce script, à chaque fois que nous assainissons un environnement, nous définissons la variable d'environnement DATA_SANITIZED afin de nous assurer que la prochaine fois que nous exécuterons ce script, il n'assainira pas l'environnement de manière répétée.

Ensuite, en fonction de la machine sur laquelle vous voulez exécuter ce script, veuillez adapter le code à vos besoins, mais il devrait ressembler à quelque chose comme ceci :

. fleet_sanitizer.sh  # or source fleet_sanitizer.sh
ORGANIZATION=<organizationIdentifier>
sanitize_organization_data $ORGANIZATION

Astuce: vous trouverez l'identifiant de l'organisation pour un projet spécifique en cliquant sur votre nom, puis sur paramètres dans le coin supérieur droit de l'écran.

Et juste comme ça, vos données sont assainies et vous êtes sur la bonne voie pour être en conformité avec le RGPD !

Si vous avez d'autres questions sur nos capacités en matière de sécurité et de conformité ou si vous rencontrez des problèmes avec les méthodes et/ou les étapes ci-dessus, contactez notre équipe d'assistance qui se fera un plaisir de vous aider.

Restez au courant des dernières nouvelles sur nos réseaux sociaux et nos canaux communautaires. Retrouvez-nous sur Dev.to, Reddit et Discord.

Votre meilleur travail
est à l'horizon

Essai gratuit
Discord
© 2025 Platform.sh. All rights reserved.