What is snowflake?
“Snowflake is a system that allows people from all over the world to access censored websites and applications. Similar to how VPNs assist users in getting around Internet censorship, Snowflake helps you avoid being noticed by Internet censors by making your Internet activity appear as though you’re using the Internet for a regular video or voice call.” (see snowflake.torproject.org)
Snowflake can run as browser plugin or as standalone proxy. The standalone proxy can be run as ansible, from source or as docker container. The container was build from the gitlab source of the TOR project and uploaded to docker hub.
It is easy to provide a standalone proxy. But in some companies the sources/URLs are not accessible due filters or other reglementations. The idea is to provide an alternative download for the docker image and an automatic deployment of the newest version to a container instance.
In order to enable the most automated deployment possible for the Snowflake Proxy, an Azure DevOps Pipeline was created, which retrieves the latest code version of the Docker Files and duplicates it in a GitHub repo. The image is rebuilt and published to Docker Hub tzuehlke/snowflake. In addition, a new container instance is created from the new image and the existing instance is deleted beforehand. The entire pipeline is also checked into the GitHub repo as
snowflake-proxy build, publish, create instance YML/JSON.
Step 0: Connections and Variables
The pipeline uses 3 connections:
- connect2dockerhub: is the connection to docker hub for uploading the new build image
- snowflake gitlab public: is the public connection to the torproject snowflake gitlab repo
- VSE2 150: is the connection to azure to deploy the container instance
The connection to github is not used from the service connections. The connection is established via shell code and with secured variables:
Step 1: Get the source
schedules: - cron: 10 18 * * 1,5 branches: include: - refs/heads/main always: true name: $(Date:yyyyMMdd)$(Rev:.r) resources: repositories: - repository: self type: git ref: refs/heads/main
The pipeline is scheduled to run on the first and fifth days of the week at 6:10 p.m. The code is retrieved from the repository of the Snowflake GitLab project. The source is not clean stored in the YAML file and is configured on the GUI as follows:
The service connection does not need username or password.
Step 2: Build Docker Image and Push to Docker Hub
- task: Docker@2 displayName: 'build image and push to docker hub' inputs: containerRegistry: connect2dockerhub repository: tzuehlke/snowflake tags: | latest $(Build.BuildNumber) env: DOCKER_BUILDKIT: 1
The Docker Task expects a
Dockerfile in the files and executes a
push. It uses the
connect2dockerhub connection. The uploaded image is tagged with the current build number
$(Build.BuildNumber) and tag
latest. It is important that the environment variable
DOCKER_BUILDKIT is set to
1, otherwise the error message
[error]failed to parse platform : "" is an invalid component of "": platform specifier component must match "^[A-Za-z0-9_-]+$": invalid argument occurs.
Step 3 and 4: Delete and Create Container Instance
- task: AzureCLI@2 displayName: 'Delete CI' inputs: azureSubscription: 'VSE2 150 ...' scriptType: pscore scriptLocation: inlineScript inlineScript: 'az container delete --name "snowflake-proxy" --resource-group "rg-snowflake" --yes' powerShellErrorActionPreference: silentlyContinue - task: AzureCLI@2 displayName: 'Create CI from docker hub' inputs: azureSubscription: 'VSE2 150 ...' scriptType: pscore scriptLocation: inlineScript inlineScript: 'az container create -g "rg-snowflake" --name "snowflake-proxy" --image tzuehlke/snowflake:latest' powerShellErrorActionPreference: silentlyContinue
az container delete and
create command to delete and recreate the container instance
snowflake-proxy in the resource group
powerShellErrorActionPreference: silentlyContinue ensures that the pieline continues to run even if the deletion fails. As source for the Image will
tzuehlke/snowflake:latest be used.
- powershell: | cd $(Agent.BuildDirectory) rm -rf snowflake/ git config --global user.name $(githubdisplayname) git config --global user.email $(githubmail) git clone https://$(githubname):$(githubtoken)@github.com/tzuehlke/snowflake.git cd snowflake cd .. cd s ren README.md README_snowflake.md copy * $(Agent.BuildDirectory)/snowflake/ cd ../snowflake git add -A git commit --allow-empty -m "update $(Build.BuildNumber)" git push --force errorActionPreference: silentlyContinue displayName: 'PS Copy and Push Code '
Logs and Costs
If the container instance is correctly deployed, a log output is generated every hour. It shows how many connections were established and how much data was uploaded and downloaded:
Without further information, a Contsiner instance with one CPU and 1.5GB RAM will be created. This generates costs of €1.22 (divided into CPU and RAM). The total costs per month are around €36.14. In this case, the outgoing traffic was less than 5GB and therefore generated no costs.