Open Bpflugrad opened 2 weeks ago
I've struggled with providing connection strings myself, providing these 'secure parameters' in a pipeline from an environment variable seems to be challenging. There may be something in my thread that helps you: https://github.com/Azure/azure-dev/issues/3597
@mip1983 thanks it looks like I might be able to work around my problem with the Variable Groups mentioned in your thread.
The really unfortunate thing is that AddParameter
works fine and azd infra synth
shows that the same behavior of turning the AddConnectionString
argument into AZURE_PASCAL_CASE
is followed but unlike Parameters the value is not brought in from remote configuration in the same way. Really seems like a bug to me.
Hi @Bpflugrad , I can explain what is happening.
When you run azd infra synth
, as you can see, azd is generating a bicep secured
parameter for the connection string:
@secure()
param BlobStorageConnection string
If you azd pipeline config
before adding the connection string to the AppHost program, azd will not ask/prompt for a value for the parameter (b/c it is not yet known). You would be using azd pipeline config
just to set up the azdo repo and service connector.
Then, when you add the connection string, run infra synth and commit the changes, your pipeline will run, but azd did not set any value for the parameter (as secret or variable) for the pipeline.
What you are doing is interesting, because you are hoping to set the env var in remote-state and have the pipeline to pick the env var from the remote state. Ideally, you should not add plain text to remote-state, as that's not a secured store. But, making the secure thing apart, azd is been able to pull the value from the remote-state to run provision
, but azd is not expecting to find the securedParameter within the environment (in .env).
Azd uses the .azure/envName/config.json
file to save the values of secured-parameters. That config.json is set in azdo as a secret, and that's where azd will try to find the value during deploying the app (for setting the value in the container app environment).
So, here's what you should be able to do, to make your sample work:
Run all your repo steps until:
Instead of running azd env set ...
do:
.azure/envName/config.json
and paste this code:
{
"infra": {
"parameters": {
"BlobStorageConnection": "YOUR_CONNECTION_STRING"
}
}
}
azd env set foo bar
. This command is just to sync and save the config.json
in your remote storage, the name of the foo and bar don't really matter. It is just a workaround to save your manual change to the config.jsonconfig.json
and restore the content of the file how it was before, probably to:
{}
This is just b/c I assume that you are trying to do remote-state to avoid writing/having the connection string in any local file. So, you can now remove it from the file, as it has been saved on remote-state.
Now you can continue with your other steps:
Execute azd infra synth
Commit
Push
Now azd will be able to fetch the value from the remote-state (from the config.json) for provison and for deploy.
Now, let me just say it again. remote-state is not meant for secured values. We are still working/designing a secured store (like KeyVault) but, remote-state should not be considered secured. For azd version 1.9.0, we update how secrets are saved in the config.json, by writing the actual secret outside of the project (inspired by .Net user secrets). So, instead of all the manual steps you are doing to set up the remote-state, you can remove the remote-state config and just do 2 changes to your project:
AZD_INITIAL_ENVIRONMENT_CONFIG
env var during provision, like: - task: AzureCLI@2
displayName: Provision Infrastructure
inputs:
azureSubscription: azconnection
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
azd provision --no-prompt --environment $(AZURE_ENV_NAME)
env:
AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
AZURE_ENV_NAME: $(AZURE_ENV_NAME)
AZURE_LOCATION: $(AZURE_LOCATION)
AZD_INITIAL_ENVIRONMENT_CONFIG: $(AZD_INITIAL_ENVIRONMENT_CONFIG)
azd pipeline config
and let azd to prompt for the connection string. Enter the connection string. azd will set the value in a secret AZD_INITIAL_ENVIRONMENT_CONFIG
automatically, and your pipeline will work.
Then, you can open the .azure/envName/config.json
and see that there is a ref to a local azd-vault, and not the raw plain text connection string, like{
"infra": {
"parameters": {
"BlobStorageConnection": "vault://1b14641c-bb16-4ee9-87f9-d5e19ef09b17/6675dd26-3372-47a7-a35e-b2026e84c2e9"
}
},
"vault": "1b14641c-bb16-4ee9-87f9-d5e19ef09b17"
}
When azd sets AZD_INITIAL_ENVIRONMENT_CONFIG, it will resolve the vault reference and write the value as a secret in azdo.
Thanks for the help @vhvb1989 this has been a lot of trial and error.
I decided to go with your second suggestion, and updated my build pipe and re-ran azd pipeline config
. I was prompted for the value, and the vault reference similar to what you pasted is in my local config.json
.
When I run the pipe now I get a lot of security errors either saying the wrong client secret was provided:
ERROR: AADSTS7000215: Invalid client secret provided. Ensure the secret being sent in the request is the client secret value, not the client secret ID, for a secret added to app '***'.
Or a panic from Go after I saved the service principal thinking it might need a new token:
panic: don't know how to prompt for type *survey.Password
My recent runs have all resulted in the panic
error, tried adding azd infra synth
back and a few other things.
This wasn't happening prior to my changes so my assumption is that attempting to resolve the vault reference is the issue. I'm not familiar with vault://
, where are those and what do they refer to?
Hi @vhvb1989,
Sorry for the confusion Friday. I figured out why I was getting the panic message. Basically, when you have used AddConnectionString("Value")
a line @secure() param Value string
is added to the main.bicep
. Even though this is only used by azd deploy
it seems that some value must exist in the .env
, even if it is just a fake value.
However, after successfully doing this, and verifying that the following appears in my remote config.json
:
{
"infra": {
"parameters": {
"BlobStorageConnection": "vault://9f52a64c-260e-4515-9d32-4b5463939db7/27440911-0f41-45f5-83f8-682a15aacdd4"
}
},
"vault": "9f52a64c-260e-4515-9d32-4b5463939db7"
}
However, azd deploy
is failing with:
2024/05/13 15:42:35 service_target_dotnet_containerapp.go:195: generating container app manifest from /home/vsts/work/1/s/AspireInfraExample.AppHost/AspireInfraExample.AppHost.csproj for project apiservice
Deploying service apiservice (Updating container app)
(x) Failed: Deploying service apiservice
ERROR: failed deploying service 'apiservice': failing invoking action 'deploy', failed executing template file: template: containerApp.tmpl.yaml:21:19: executing "containerApp.tmpl.yaml" at <securedParameter "BlobStorageConnection">: error calling securedParameter: parameter BlobStorageConnection not found
I am not using azd infra synth
in this case. I also changed the slashes from backslash \
to forward slash /
in azure.yaml
since you mentioned the regression in #3891 but that didn't make a difference.
If I do use azd infra synth
I end up with:
2024/05/13 15:53:22 service_target_dotnet_containerapp.go:186: using container app manifest from /home/vsts/work/1/s/AspireInfraExample.AppHost/infra/apiservice.tmpl.yaml
panic: send on closed channel
goroutine 66 [running]:
github.com/azure/azure-dev/cli/azd/pkg/async.(*TaskContextWithProgress[...]).SetProgress(...)
/mnt/vss/_work/1/s/cli/azd/pkg/async/task_context.go:74
github.com/azure/azure-dev/cli/azd/pkg/project.syncProgress[...](0xc0004ad380, 0x0)
/mnt/vss/_work/1/s/cli/azd/pkg/project/service_manager.go:678 +0xbd
created by github.com/azure/azure-dev/cli/azd/pkg/project.runCommand[...].func1 in goroutine 28
/mnt/vss/_work/1/s/cli/azd/pkg/project/service_manager.go:658 +0xb9
Also after each failed deployment the remote config.json
is reset to {}
so I have to do azd env set
with a fake value each time. I made sure to run azd pipeline config
so that AZD_INITIAL_ENVIRONMENT_CONFIG
would be updated (I can't validate its content from Azure DevOps). I am passing AZD_INITIAL_ENVIRONMENT_CONFIG
as env to both azd provision
and azd deploy
in my pipeline:
- task: AzureCLI@2
displayName: Provision Infrastructure
inputs:
azureSubscription: azconnection
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
azd provision --no-prompt
env:
AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
AZURE_ENV_NAME: $(AZURE_ENV_NAME)
AZURE_LOCATION: $(AZURE_LOCATION)
AZD_INITIAL_ENVIRONMENT_CONFIG: $(AZD_INITIAL_ENVIRONMENT_CONFIG)
- task: AzureCLI@2
displayName: Deploy Application
inputs:
azureSubscription: azconnection
scriptType: bash
scriptLocation: inlineScript
inlineScript: |
azd deploy --no-prompt --debug
env:
AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
AZURE_ENV_NAME: $(AZURE_ENV_NAME)
AZURE_LOCATION: $(AZURE_LOCATION)
AZD_INITIAL_ENVIRONMENT_CONFIG: $(AZD_INITIAL_ENVIRONMENT_CONFIG)
You only mentioned adding AZD_INITIAL_ENVIRONMENT_CONFIG
to azd provision
but I figured since the value is needed in azd deploy
that it wouldn't hurt to have it on both.
Anyway, perhaps I missed a step but I can't get your second suggestion to work.
Any help is appreciated!
@Bpflugrad , #3891 was not the only issue affecting azd on CI/CD. There was also https://github.com/Azure/azure-dev/pull/3897. The fix was merged already, but you need daily-build to get it. There's 2 things you can do:
azd pipeline config
, update the config.json from what you have:
{
"infra": {
"parameters": {
"BlobStorageConnection": "vault://9f52a64c-260e-4515-9d32-4b5463939db7/27440911-0f41-45f5-83f8-682a15aacdd4"
}
},
"vault": "9f52a64c-260e-4515-9d32-4b5463939db7"
}
to what it should be in CI:
{
"infra": {
"parameters": {
"BlobStorageConnection": "The actual connection string HERE"
}
},
}
The issue on 1.9.0 is that azd is setting the config.json like:
{
"infra": {
"parameters": {
"BlobStorageConnection": "The actual connection string HERE"
}
},
"vault": "9f52a64c-260e-4515-9d32-4b5463939db7"
}
You can see that the secrets are resolved, but the vault
field is still there, and when runining in CI, azd will not find that vault and will just create an empty config. In the fix in daily, azd is removing the vault
field for the resolved-config
Thanks @vhvb1989. I updated to the daily build. The workaround (your second suggestion) where the raw value is included in config.json
works.
However, using azd
naturally (your first suggestion), including the secured values with the vault references still doesn't work. I updated both the build pipe and local azd
to 1.10.0-beta.1-daily.3780018 (commit bb526cbd20cfbd9d2ebadc2e34f1058e8595ff4f)
.
I'm still getting panic: send on closed channel
2024/05/13 21:22:15 service_target_dotnet_containerapp.go:195: generating container app manifest from /home/vsts/work/1/s/AspireInfraExample.AppHost/AspireInfraExample.AppHost.csproj for project apiservice
panic: send on closed channel
goroutine 56 [running]:
github.com/azure/azure-dev/cli/azd/pkg/async.(*TaskContextWithProgress[...]).SetProgress(...)
/mnt/vss/_work/1/s/cli/azd/pkg/async/task_context.go:74
github.com/azure/azure-dev/cli/azd/pkg/project.syncProgress[...](0xc0004c0690, 0x0)
/mnt/vss/_work/1/s/cli/azd/pkg/project/service_manager.go:689 +0xbd
created by github.com/azure/azure-dev/cli/azd/pkg/project.runCommand[...].func1 in goroutine 35
/mnt/vss/_work/1/s/cli/azd/pkg/project/service_manager.go:669 +0xb9
After updating the azd
version to the daily build, I reran azd pipeline config
just in case vault creation and resolution had changed.
Thanks again for your help, I can at least proceed with the insecure workaround until the vaults can be figured out.
Hi @vhvb1989 ,
I tried a few permutations of my build script. If I have AZD_INITIAL_ENVIRONMENT_CONFIG
only on azd provision
or only on azd deploy
, I get the missing parameter error message from azd deploy
like:
ERROR: failed deploying service 'apiservice': failed executing template file: template: containerApp.tmpl.yaml:21:19: executing "containerApp.tmpl.yaml" at <securedParameter "BlobStorageConnection">: error calling securedParameter: parameter BlobStorageConnection not found
If I have AZD_INITIAL_ENVIRONMENT_CONFIG
on BOTH azd provision
and azd deploy
I get the panic message:
panic: send on closed channel
goroutine 56 [running]:
github.com/azure/azure-dev/cli/azd/pkg/async.(*TaskContextWithProgress[...]).SetProgress(...)
/mnt/vss/_work/1/s/cli/azd/pkg/async/task_context.go:74
github.com/azure/azure-dev/cli/azd/pkg/project.syncProgress[...](0xc0004c0690, 0x0)
/mnt/vss/_work/1/s/cli/azd/pkg/project/service_manager.go:689 +0xbd
created by github.com/azure/azure-dev/cli/azd/pkg/project.runCommand[...].func1 in goroutine 35
/mnt/vss/_work/1/s/cli/azd/pkg/project/service_manager.go:669 +0xb9
I've never worked with Go before but looking at this stack trace, service_manager.go
and service_target_dotnet_containerapp.go
it appears that there's a silent failure between here and here.
Somehow ServiceProgress
is getting closed and causing the send on closed channel
. At least that is my guess.
Hi @Bpflugrad
We just released 1.9.1 which should have a fix for how AZD_INITIAL_ENVIRONMENT_CONFIG
is set when you run azd pipeline config
Can you try using 1.9.1 to run azd pipeline config
please. Let me know what you get
Hi @vhvb1989,
Thanks for the reply. I updated my local machine to 1.9.1 (commit aadbc26943c2e3e5437a6ffa528fe5264887a10c)
, and I updated the pipeline to not use the daily build anymore, confirmed it is using the same version.
I took the following steps:
config.json
, remove my related stub AZURE_BLOB_STORAGE_CONNECTION
from .env
.azd pipeline config
, enter my secret value.azd env set AZURE_BLOB_STORAGE_CONNECTION blah12
to avoid failure in azd provision
azd infra synth
to check that no changes there have been made (none had)Unfortunately, azd deploy
still fails with panic: send on closed channel
.
Output from
azd version
Runazd version
and copy and paste the output here:azd version 1.8.2 (commit 14600c7a54edac4f54397413f8638431f5c16327)
Describe the bug Deploying in an azdo pipeline:
Using Aspire preview 6
8.0.0-preview.6.24214.1
. UsingAddConnectionString(string)
to add a reference to an existing Azure resource by connection string. When deploying in an azdo pipeline, if a deployment has never been completed before (such as withazd up
on a development machine),azd deploy
fails with error message:This causes the pipeline to fail and deployment cannot be completed.
To Reproduce
Visual Studio 17.10.0 Preview 5.0
create a new project from template .Net Aspire Starter Project.azd init
in the Solution folder.azure.yaml
adding to the root:.azdo\pipelines
azure-dev.yml
azd pipeline config
, following all instructions related to PAT, remotes, etc.azconnection
service principal withStorage Blob Contributor
for Storage Account STORAGE_ACCOUNT.AppHost.Program
with the following line:var blobStorageConnectionString = builder.AddConnectionString("BlobStorageConnection");
AddProject
line, adding.WithReference(blobStorageConnectionString)
.ApiService.Program
adding:builder.AddAzureBlobClient("BlobStorageConnection");
azure-dev.yml
to add build commands:pool: vmImage: ubuntu-latest
steps:
task: DotNetCoreCLI@2 displayName: Install Aspire Workload with Preview inputs: command: custom custom: 'workload' arguments: 'install aspire --include-previews --source https://api.nuget.org/v3/index.json'
task: setup-azd@0 displayName: Install azd
pwsh: | azd config set auth.useAzCliAuth "true" displayName: Configure AZD to Use AZ CLI Authentication.
task: AzureCLI@2 displayName: Provision Infrastructure inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript inlineScript: | azd provision --no-prompt --environment $(AZURE_ENV_NAME) env: AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID) AZURE_ENV_NAME: $(AZURE_ENV_NAME) AZURE_LOCATION: $(AZURE_LOCATION)
task: AzureCLI@2 displayName: Deploy Application inputs: azureSubscription: azconnection scriptType: bash scriptLocation: inlineScript inlineScript: | azd deploy --no-prompt --environment $(AZURE_ENV_NAME) env: AZURE_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID) AZURE_ENV_NAME: $(AZURE_ENV_NAME) AZURE_LOCATION: $(AZURE_LOCATION)
Note that in
main.parameters.json
added by this command that the following line exists:The build will be triggered, and at the
Deploy Application
step will fail with error:Expected behavior Deployment should succeed since the required parameter is present in the environment.
Environment Information on your environment:
dotnet --version 8.0.300-preview.24203.14
Visual Studio 17.10.0 Preview 5.0
8.0.0-preview.6.24214.1
azd version 1.8.2 (commit 14600c7a54edac4f54397413f8638431f5c16327)
Additional context When not using
azd infra synth
the error is slightly different:Also tried to updating the
builder.AddConnectionString("BlobStorageConnection", "AZURE_BLOB_STORAGE_CONNECTION");
and still get the panic.