6

I'm writing a testing pipeline and dynamically creating a series of containers to setup the pieces.

I need to be able to pass a secret variable from the Pipeline into the Docker Compose construct to enable the container to connect to the database server.

I have a number of non-secret variables in the pipeline and they are all being passed successfully.

I have mapped the $env:addressdatabase_password in a powershell test to verify that my variable is available.

#To Verify if mapped secret variables are coming through (reverse the string)
- powershell: |
    $a = $env:addressdatabase_password
    Write-Host "$a"
    $b = $a.ToCharArray()
    [Array]::Reverse($b)
    $c = -join($b)
    Write-Host "$c"
  env:
    addressdatabase_password: $(database-address-password) #pipeline secret

The task in my azure-pipelines.yml looks like this (not all arguments are shown)

- task: DockerCompose@0
  displayName: 'Container Start'
  inputs:
    containerregistrytype: 'Azure Container Registry'
    azureSubscription: '$(containerSubscription)'
    azureContainerRegistry: '{"loginServer":"$(containerLoginServer)", "id" : "$(containerRegistryId)"}'
    dockerComposeFile: '**/docker-compose.yml'
    action: 'Run a Docker Compose command'
    dockerComposeCommand: 'up -d'
    arguments: mycontainer
    containerName: 'cf_$(CreateDb.buildidentifier)'
    detached: true
    dockerComposeFileArgs: |
      addressdatabase_name=$(database-address-name)
      addressdatabase_user=$(database-address-user)
      addressdatabase_pass=$(addressdatabase_password)
  env:
    addressdatabase_password: $(database-address-password) #pipeline secret

The relevant parts of the docker-compose.yml file

  mycontainer:
    image: mycontainer-runtime:latest
    ports:
      - "80:80"
    volumes:
      - ${mount_1}:C:/mount1
      - ${mount_2}:C:/mount2
    environment:
      ADDRESS_DATABASE_NAME: ${addressdatabase_name}
      ADDRESS_DATABASE_USERNAME: ${addressdatabase_user}
      ADDRESS_DATABASE_PASSWORD: ${addressdatabase_pass} #pipeline secret

The container starts up successfully, but when I examine the Environment Variables inside the container

ADDRESS_DATABASE_NAME=pr_address
ADDRESS_DATABASE_USER=test-addressuser
ADDRESS_DATABASE_PASSWORD=$(addressdatabase_password)

I'm looking for a way to get this value securely to my container without exposing it in the Pipeline.

Paul Farry
  • 4,730
  • 2
  • 35
  • 61
  • What do you mean by "*without exposing it in the Pipeline*"? I quess it should be possible to create a secured connection but the user that uses the `test-addressuser` account will always beable to figure out the password as any (decryption) script that runs under that account is required to do so in such a design. In other words, any attempt to encrypt/decrypt will likely end up in a [**Security through obscurity**](https://en.wikipedia.org/wiki/Security_through_obscurity). The security should come from your database setup: don't share a accounts, but add each (docker) user to database. – iRon Jun 14 '21 at 11:19
  • @iRon, the variable is a secret inside the pipeline itself, using the checkbox. I don't want people running the pipeline itself to be able to view the password, as you can see from my powershell code block I know how to get the password back out, I just don't want people editing/using verbatim from "Edit Variables" directly in the pipeline. I just want to be able to pass the variable into the Docker Compose from a secret in the pipeline. Once inside the container, all bets are off. – Paul Farry Jun 14 '21 at 23:20

1 Answers1

0

Mapping pipeline secrets to env vars is just a way of passing secrets to scripts. For other types of tasks, you should be able to use the secret directly in inputs, i.e.:

- task: DockerCompose@0
  displayName: 'Container Start'
  inputs:
    containerregistrytype: 'Azure Container Registry'
    azureSubscription: '$(containerSubscription)'
    azureContainerRegistry: '{"loginServer":"$(containerLoginServer)", "id" : "$(containerRegistryId)"}'
    dockerComposeFile: '**/docker-compose.yml'
    action: 'Run a Docker Compose command'
    dockerComposeCommand: 'up -d'
    arguments: mycontainer
    containerName: 'cf_$(CreateDb.buildidentifier)'
    detached: true
    dockerComposeFileArgs: |
      addressdatabase_name=$(database-address-name)
      addressdatabase_user=$(database-address-user)
      addressdatabase_pass=$(database-address-password) 

The secret value will still be masked in the logs, no matter how you pass it.

qbik
  • 5,502
  • 2
  • 27
  • 33