Browse Source

Use environment variables for secrets in prod (#315)

* Use environment variables for secrets
- Updating in place does not apply to connection strings specifically since they are usually configured at startup as singletons.
- This brings consistency with the development experience.
- Gets rid of AddTyeBindings
- "Less secure", sure but to be pedantic env variables are stored in virtual file on disk while the process is running. I'd argue if you want full security then use keyvault/vault/name your secret store.

Fixes #313

* Removed the last AddTyeSecrets call
pull/327/head
David Fowler 6 years ago
committed by GitHub
parent
commit
84bb3bf488
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      docs/redis.md
  2. 20
      docs/service_discovery.md
  3. 4
      samples/multi-project/backend/Program.cs
  4. 4
      samples/multi-project/frontend/Program.cs
  5. 4
      samples/multi-project/worker/Program.cs
  6. 1
      samples/voting/vote/Program.cs
  7. 2
      samples/voting/worker/Program.cs
  8. 6
      src/Microsoft.Tye.Core/CombineStep.cs
  9. 14
      src/Microsoft.Tye.Core/ComputedBindings.cs
  10. 145
      src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs
  11. 4
      src/Microsoft.Tye.Core/ValidateSecretStep.cs
  12. 44
      src/Microsoft.Tye.Extensions.Configuration/TyeSecretsConfigurationBuilderExtensions.cs
  13. 37
      src/Microsoft.Tye.Extensions.Configuration/TyeSecretsConfigurationSource.cs
  14. 18
      test/E2ETest/testassets/generate/generate-connectionstring-dependency.yaml
  15. 32
      test/E2ETest/testassets/generate/generate-named-binding.yaml
  16. 32
      test/E2ETest/testassets/generate/generate-uri-dependency.yaml
  17. 96
      test/E2ETest/testassets/generate/multi-project.yaml

31
docs/redis.md

@ -126,34 +126,7 @@ We just showed how `tye` makes it easier to communicate between 2 applications r
You will see redis deployed and running.
2. Add secrets to the application
In order to access redis we need to add some code to the `backend` project to be able to read secrets from inside the container.
First, add the Tye configuration provider package to the backend project using the command line.
```text
cd backend
dotnet add package Microsoft.Tye.Extensions.Configuration --version "0.1.0-*"
cd ..
```
Then update `CreateHostBuilder` in `Program.cs` of the `backend` project to create the configuration source:
```C#
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
config.AddTyeSecrets();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
```
3. Deploy to Kubernetes
2. Deploy to Kubernetes
Next, deploy the rest of the application by running:
@ -186,7 +159,7 @@ We just showed how `tye` makes it easier to communicate between 2 applications r
> :bulb: Tye uses kubernetes secrets to store connection information about dependencies like redis that might live outside the cluster. Tye will automatically generate mappings between service names, binding names, and secret names.
4. Test it out!
3. Test it out!
You should now see three pods running after deploying.

20
docs/service_discovery.md

@ -286,22 +286,4 @@ stringData:
Creating the secret is a one-time operation, and Tye will only prompt for it if it does not already exist. If desired you can use standard `kubectl` commands to update values or delete the secret and force it to be recreated.
To get these values into the application, Tye will use Kubernetes volume mounts to create files on disk inside the container. Currrently these files will be placed in `/var/tye/bindings/<service>-<binding>/` and will use the environment-variable naming scheme described above.
Inside the application, adding the Tye secrets provider will add these to the configuration.
```C#
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
// Add Tye secrets
config.AddTyeSecrets();
})
.ConfigureWebHostDefaults(web =>
{
web.UseStartup<Startup>();
});
```
Tye will also inject the `TYE_SECRETS_PATH` environment variable with the value `/var/tye/bindings/`. This is done to avoid hardcoding a file-system path in the configuration provider.
To get these values into the application, Tye will use environment variables that reference the Kubernetes secrets described above and will use the environment-variable naming scheme described above.

4
samples/multi-project/backend/Program.cs

@ -23,10 +23,6 @@ namespace Backend
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
config.AddTyeSecrets();
})
.ConfigureWebHostDefaults(web =>
{
web.UseStartup<Startup>()

4
samples/multi-project/frontend/Program.cs

@ -22,10 +22,6 @@ namespace Frontend
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
config.AddTyeSecrets();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();

4
samples/multi-project/worker/Program.cs

@ -20,10 +20,6 @@ namespace Worker
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(config =>
{
config.AddTyeSecrets();
})
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<QueueWorker>();

1
samples/voting/vote/Program.cs

@ -26,7 +26,6 @@ namespace Vote
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder => builder.AddTyeSecrets())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();

2
samples/voting/worker/Program.cs

@ -6,7 +6,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Hosting;
using System.IO;
namespace Worker
{
@ -19,7 +18,6 @@ namespace Worker
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder => builder.AddTyeSecrets())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();

6
src/Microsoft.Tye.Core/CombineStep.cs

@ -111,11 +111,11 @@ namespace Microsoft.Tye
// The other service is not a project, so we'll use secrets.
if (!string.IsNullOrEmpty(binding.ConnectionString))
{
bindings.Bindings.Add(new SecretConnctionStringInputBinding(
bindings.Bindings.Add(new SecretConnectionStringInputBinding(
name: $"binding-{Environment}-{(binding.Name == null ? other.Name.ToLowerInvariant() : (other.Name.ToLowerInvariant() + "-" + binding.Name.ToLowerInvariant()))}-secret",
other,
binding,
filename: $"CONNECTIONSTRINGS__{(binding.Name == null ? other.Name.ToUpperInvariant() : (other.Name.ToUpperInvariant() + "__" + binding.Name.ToUpperInvariant()))}"));
keyname: $"CONNECTIONSTRINGS__{(binding.Name == null ? other.Name.ToUpperInvariant() : (other.Name.ToUpperInvariant() + "__" + binding.Name.ToUpperInvariant()))}"));
}
else
{
@ -123,7 +123,7 @@ namespace Microsoft.Tye
name: $"binding-{Environment}-{(binding.Name == null ? other.Name.ToLowerInvariant() : (other.Name.ToLowerInvariant() + "-" + binding.Name.ToLowerInvariant()))}-secret",
other,
binding,
filenameBase: $"SERVICE__{(binding.Name == null ? other.Name.ToUpperInvariant() : (other.Name.ToUpperInvariant() + "__" + binding.Name.ToUpperInvariant()))}"));
keynamebase: $"SERVICE__{(binding.Name == null ? other.Name.ToUpperInvariant() : (other.Name.ToUpperInvariant() + "__" + binding.Name.ToUpperInvariant()))}"));
}
}
}

14
src/Microsoft.Tye.Core/ComputedBindings.cs

@ -43,33 +43,33 @@ namespace Microsoft.Tye
public BindingBuilder Binding { get; }
}
public sealed class SecretConnctionStringInputBinding : SecretInputBinding
public sealed class SecretConnectionStringInputBinding : SecretInputBinding
{
public SecretConnctionStringInputBinding(string name, ServiceBuilder service, BindingBuilder binding, string filename)
public SecretConnectionStringInputBinding(string name, ServiceBuilder service, BindingBuilder binding, string keyname)
: base(name, service, binding)
{
Filename = filename;
KeyName = keyname;
}
// Used to generate a kubernetes secret
public string? Value { get; }
// Used to map the secret to a key that ASP.NET Core understands
public string Filename { get; }
public string KeyName { get; }
}
public sealed class SecretUrlInputBinding : SecretInputBinding
{
public SecretUrlInputBinding(string name, ServiceBuilder service, BindingBuilder binding, string filenameBase)
public SecretUrlInputBinding(string name, ServiceBuilder service, BindingBuilder binding, string keynamebase)
: base(name, service, binding)
{
FilenameBase = filenameBase;
KeyNameBase = keynamebase;
}
// Used to generate a kubernetes secret
public string? Value { get; }
// Used to map the secret to keys that ASP.NET Core understands
public string FilenameBase { get; }
public string KeyNameBase { get; }
}
}

145
src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs

@ -211,33 +211,82 @@ namespace Microsoft.Tye
});
}
if (bindings.Bindings.OfType<SecretInputBinding>().Any())
foreach (var binding in bindings.Bindings.OfType<SecretInputBinding>())
{
env.Add(new YamlMappingNode()
//- name: SECRET_USERNAME
// valueFrom:
// secretKeyRef:
// name: mysecret
// key: username
if (binding is SecretConnectionStringInputBinding connectionStringBinding)
{
{ "name", "TYE_SECRETS_PATH" },
{ "value", new YamlScalarNode("/var/tye/bindings/") { Style = ScalarStyle.SingleQuoted, } },
});
env.Add(new YamlMappingNode()
{
{ "name", connectionStringBinding.KeyName },
{ "valueFrom", new YamlMappingNode()
{
{ "secretKeyRef", new YamlMappingNode()
{
{ "name", new YamlScalarNode(binding.Name) { Style = ScalarStyle.SingleQuoted } },
{ "key", new YamlScalarNode("connectionString") { Style = ScalarStyle.SingleQuoted } },
}
},
}
},
});
}
else if (binding is SecretUrlInputBinding urlBinding)
{
env.Add(new YamlMappingNode()
{
{ "name", $"{urlBinding.KeyNameBase}__PROTOCOL" },
{ "valueFrom", new YamlMappingNode()
{
{ "secretKeyRef", new YamlMappingNode()
{
{ "name", new YamlScalarNode(binding.Name) { Style = ScalarStyle.SingleQuoted } },
{ "key", new YamlScalarNode("protocol") { Style = ScalarStyle.SingleQuoted } },
}
},
}
},
});
env.Add(new YamlMappingNode()
{
{ "name", $"{urlBinding.KeyNameBase}__HOST" },
{ "valueFrom", new YamlMappingNode()
{
{ "secretKeyRef", new YamlMappingNode()
{
{ "name", new YamlScalarNode(binding.Name) { Style = ScalarStyle.SingleQuoted } },
{ "key", new YamlScalarNode("host") { Style = ScalarStyle.SingleQuoted } },
}
},
}
},
});
env.Add(new YamlMappingNode()
{
{ "name", $"{urlBinding.KeyNameBase}__PORT" },
{ "valueFrom", new YamlMappingNode()
{
{ "secretKeyRef", new YamlMappingNode()
{
{ "name", new YamlScalarNode(binding.Name) { Style = ScalarStyle.SingleQuoted } },
{ "key", new YamlScalarNode("port") { Style = ScalarStyle.SingleQuoted } },
}
},
}
},
});
}
}
}
}
if (bindings is object && bindings.Bindings.OfType<SecretInputBinding>().Any())
{
var volumeMounts = new YamlSequenceNode();
container.Add("volumeMounts", volumeMounts);
foreach (var binding in bindings.Bindings.OfType<SecretInputBinding>())
{
var volumeMount = new YamlMappingNode();
volumeMounts.Add(volumeMount);
volumeMount.Add("name", $"binding-{(binding.Binding.Name == null ? binding.Service.Name.ToLowerInvariant() : (binding.Service.Name.ToLowerInvariant() + "-" + binding.Binding.Name.ToLowerInvariant()))}");
volumeMount.Add("mountPath", $"/var/tye/bindings/{(binding.Binding.Name == null ? binding.Service.Name.ToLowerInvariant() : (binding.Service.Name.ToLowerInvariant() + "-" + binding.Binding.Name.ToLowerInvariant()))}");
volumeMount.Add("readOnly", "true");
}
}
if (project.Bindings.Count > 0)
{
var ports = new YamlSequenceNode();
@ -262,60 +311,6 @@ namespace Microsoft.Tye
}
}
if (bindings.Bindings.OfType<SecretInputBinding>().Any())
{
var volumes = new YamlSequenceNode();
spec.Add("volumes", volumes);
foreach (var binding in bindings.Bindings.OfType<SecretConnctionStringInputBinding>())
{
var volume = new YamlMappingNode();
volumes.Add(volume);
volume.Add("name", $"binding-{(binding.Binding.Name == null ? binding.Service.Name.ToLowerInvariant() : (binding.Service.Name.ToLowerInvariant() + "-" + binding.Binding.Name.ToLowerInvariant()))}");
var secret = new YamlMappingNode();
volume.Add("secret", secret);
secret.Add("secretName", binding.Name);
var items = new YamlSequenceNode();
secret.Add("items", items);
var item = new YamlMappingNode();
items.Add(item);
item.Add("key", "connectionstring");
item.Add("path", binding.Filename);
}
foreach (var binding in bindings.Bindings.OfType<SecretUrlInputBinding>())
{
var volume = new YamlMappingNode();
volumes.Add(volume);
volume.Add("name", $"binding-{(binding.Binding.Name == null ? binding.Service.Name.ToLowerInvariant() : (binding.Service.Name.ToLowerInvariant() + "-" + binding.Binding.Name.ToLowerInvariant()))}");
var secret = new YamlMappingNode();
volume.Add("secret", secret);
secret.Add("secretName", binding.Name);
var items = new YamlSequenceNode();
secret.Add("items", items);
var item = new YamlMappingNode();
items.Add(item);
item.Add("key", "protocol");
item.Add("path", binding.FilenameBase + "__PROTOCOL");
item = new YamlMappingNode();
items.Add(item);
item.Add("key", "host");
item.Add("path", binding.FilenameBase + "__HOST");
item = new YamlMappingNode();
items.Add(item);
item.Add("key", "port");
item.Add("path", binding.FilenameBase + "__PORT");
}
}
return new KubernetesDeploymentOutput(project.Name, new YamlDocument(root));
}
}

4
src/Microsoft.Tye.Core/ValidateSecretStep.cs

@ -83,7 +83,7 @@ namespace Microsoft.Tye
continue;
}
if (!Interactive && secretInputBinding is SecretConnctionStringInputBinding)
if (!Interactive && secretInputBinding is SecretConnectionStringInputBinding)
{
throw new CommandException(
$"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " +
@ -102,7 +102,7 @@ namespace Microsoft.Tye
}
V1Secret secret;
if (secretInputBinding is SecretConnctionStringInputBinding)
if (secretInputBinding is SecretConnectionStringInputBinding)
{
// If we get here then we should create the secret.
var text = output.Prompt($"Enter the connection string to use for service '{secretInputBinding.Service.Name}'", allowEmpty: true);

44
src/Microsoft.Tye.Extensions.Configuration/TyeSecretsConfigurationBuilderExtensions.cs

@ -1,44 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using Microsoft.Extensions.FileProviders;
namespace Microsoft.Extensions.Configuration
{
/// <summary>
/// Contains extension methods for adding Tye's secrets to <see cref="IConfiguration" />.
/// </summary>
public static class TyeSecretsConfigurationBuilderExtensions
{
/// <summary>
/// Adds Tye's secrets to <see cref="IConfiguration" />.
/// </summary>
/// <param name="builder">The <see cref="IConfigurationBuilder" />.</param>
/// <returns>The <see cref="IConfigurationBuilder" />.</returns>
/// <remarks>
/// The environment variable <c>TYE_SECRETS_PATH</c> is used to populate the directory used by secrets.
/// When the environment variable is specified, and the specified directory exists, then the value of
/// <see cref="TyeSecretsConfigurationSource.FileProvider" /> will be non-null.
/// </remarks>
public static IConfigurationBuilder AddTyeSecrets(this IConfigurationBuilder builder)
{
var secretsDirectory = Environment.GetEnvironmentVariable(TyeSecretsConfigurationSource.TyeSecretsPathEnvironmentVariable);
if (Directory.Exists(secretsDirectory))
{
foreach (var child in Directory.EnumerateDirectories(secretsDirectory))
{
var source = new TyeSecretsConfigurationSource()
{
FileProvider = new PhysicalFileProvider(child),
};
builder.Add(source);
}
}
return builder;
}
}
}

37
src/Microsoft.Tye.Extensions.Configuration/TyeSecretsConfigurationSource.cs

@ -1,37 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Extensions.Configuration.KeyPerFile;
using Microsoft.Extensions.FileProviders;
namespace Microsoft.Extensions.Configuration
{
/// <summary>
/// An <see cref="IConfigurationSource" /> implementation for Tye's secrets.
/// </summary>
public sealed class TyeSecretsConfigurationSource : IConfigurationSource
{
/// <summary>
/// The environment variable used to configure the path where Tye looks for secrets.
/// </summary>
public static readonly string TyeSecretsPathEnvironmentVariable = "TYE_SECRETS_PATH";
/// <summary>
/// Gets or sets the <see cref="IFileProvider" /> used by the configuration source.
/// </summary>
public IFileProvider? FileProvider { get; set; }
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
var source = new KeyPerFileConfigurationSource()
{
FileProvider = FileProvider,
Optional = true,
};
return source.Build(builder);
}
}
}

18
test/E2ETest/testassets/generate/generate-connectionstring-dependency.yaml

@ -25,21 +25,13 @@ spec:
value: 'http://*'
- name: PORT
value: '80'
- name: TYE_SECRETS_PATH
value: '/var/tye/bindings/'
volumeMounts:
- name: binding-dependency
mountPath: /var/tye/bindings/dependency
readOnly: true
- name: CONNECTIONSTRINGS__DEPENDENCY
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-secret'
key: 'connectionString'
ports:
- containerPort: 80
volumes:
- name: binding-dependency
secret:
secretName: binding-production-dependency-secret
items:
- key: connectionstring
path: CONNECTIONSTRINGS__DEPENDENCY
...
---
kind: Service

32
test/E2ETest/testassets/generate/generate-named-binding.yaml

@ -25,25 +25,23 @@ spec:
value: 'http://*'
- name: PORT
value: '80'
- name: TYE_SECRETS_PATH
value: '/var/tye/bindings/'
volumeMounts:
- name: binding-dependency-mybinding
mountPath: /var/tye/bindings/dependency-mybinding
readOnly: true
- name: SERVICE__DEPENDENCY__MYBINDING__PROTOCOL
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-mybinding-secret'
key: 'protocol'
- name: SERVICE__DEPENDENCY__MYBINDING__HOST
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-mybinding-secret'
key: 'host'
- name: SERVICE__DEPENDENCY__MYBINDING__PORT
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-mybinding-secret'
key: 'port'
ports:
- containerPort: 80
volumes:
- name: binding-dependency-mybinding
secret:
secretName: binding-production-dependency-mybinding-secret
items:
- key: protocol
path: SERVICE__DEPENDENCY__MYBINDING__PROTOCOL
- key: host
path: SERVICE__DEPENDENCY__MYBINDING__HOST
- key: port
path: SERVICE__DEPENDENCY__MYBINDING__PORT
...
---
kind: Service

32
test/E2ETest/testassets/generate/generate-uri-dependency.yaml

@ -25,25 +25,23 @@ spec:
value: 'http://*'
- name: PORT
value: '80'
- name: TYE_SECRETS_PATH
value: '/var/tye/bindings/'
volumeMounts:
- name: binding-dependency
mountPath: /var/tye/bindings/dependency
readOnly: true
- name: SERVICE__DEPENDENCY__PROTOCOL
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-secret'
key: 'protocol'
- name: SERVICE__DEPENDENCY__HOST
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-secret'
key: 'host'
- name: SERVICE__DEPENDENCY__PORT
valueFrom:
secretKeyRef:
name: 'binding-production-dependency-secret'
key: 'port'
ports:
- containerPort: 80
volumes:
- name: binding-dependency
secret:
secretName: binding-production-dependency-secret
items:
- key: protocol
path: SERVICE__DEPENDENCY__PROTOCOL
- key: host
path: SERVICE__DEPENDENCY__HOST
- key: port
path: SERVICE__DEPENDENCY__PORT
...
---
kind: Service

96
test/E2ETest/testassets/generate/multi-project.yaml

@ -31,25 +31,23 @@ spec:
value: '8000'
- name: SERVICE__FRONTEND__HOST
value: 'frontend'
- name: TYE_SECRETS_PATH
value: '/var/tye/bindings/'
volumeMounts:
- name: binding-rabbit
mountPath: /var/tye/bindings/rabbit
readOnly: true
- name: SERVICE__RABBIT__PROTOCOL
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'protocol'
- name: SERVICE__RABBIT__HOST
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'host'
- name: SERVICE__RABBIT__PORT
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'port'
ports:
- containerPort: 7000
volumes:
- name: binding-rabbit
secret:
secretName: binding-production-rabbit-secret
items:
- key: protocol
path: SERVICE__RABBIT__PROTOCOL
- key: host
path: SERVICE__RABBIT__HOST
- key: port
path: SERVICE__RABBIT__PORT
...
---
kind: Service
@ -103,25 +101,23 @@ spec:
value: '7000'
- name: SERVICE__BACKEND__HOST
value: 'backend'
- name: TYE_SECRETS_PATH
value: '/var/tye/bindings/'
volumeMounts:
- name: binding-rabbit
mountPath: /var/tye/bindings/rabbit
readOnly: true
- name: SERVICE__RABBIT__PROTOCOL
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'protocol'
- name: SERVICE__RABBIT__HOST
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'host'
- name: SERVICE__RABBIT__PORT
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'port'
ports:
- containerPort: 8000
volumes:
- name: binding-rabbit
secret:
secretName: binding-production-rabbit-secret
items:
- key: protocol
path: SERVICE__RABBIT__PROTOCOL
- key: host
path: SERVICE__RABBIT__HOST
- key: port
path: SERVICE__RABBIT__PORT
...
---
kind: Service
@ -177,21 +173,19 @@ spec:
value: '8000'
- name: SERVICE__FRONTEND__HOST
value: 'frontend'
- name: TYE_SECRETS_PATH
value: '/var/tye/bindings/'
volumeMounts:
- name: binding-rabbit
mountPath: /var/tye/bindings/rabbit
readOnly: true
volumes:
- name: binding-rabbit
secret:
secretName: binding-production-rabbit-secret
items:
- key: protocol
path: SERVICE__RABBIT__PROTOCOL
- key: host
path: SERVICE__RABBIT__HOST
- key: port
path: SERVICE__RABBIT__PORT
- name: SERVICE__RABBIT__PROTOCOL
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'protocol'
- name: SERVICE__RABBIT__HOST
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'host'
- name: SERVICE__RABBIT__PORT
valueFrom:
secretKeyRef:
name: 'binding-production-rabbit-secret'
key: 'port'
...

Loading…
Cancel
Save