feat(deployment): add secure Linux runtime (#17)
This commit is contained in:
@@ -40,18 +40,32 @@ internal sealed class SecretMaterial : IDisposable
|
||||
|
||||
internal sealed class EnvironmentSecretProvider : ISecretProvider
|
||||
{
|
||||
private const string Prefix = "env:";
|
||||
private const string EnvironmentPrefix = "env:";
|
||||
private const string FilePrefix = "file:";
|
||||
private const int MaximumSecretBytes = 4096;
|
||||
|
||||
public bool TryGetSecret(string reference, out SecretMaterial? secret)
|
||||
{
|
||||
secret = null;
|
||||
if (!reference.StartsWith(Prefix, StringComparison.Ordinal)
|
||||
|| reference.Length == Prefix.Length)
|
||||
if (reference.StartsWith(EnvironmentPrefix, StringComparison.Ordinal)
|
||||
&& reference.Length > EnvironmentPrefix.Length)
|
||||
{
|
||||
return false;
|
||||
return TryGetEnvironmentSecret(reference[EnvironmentPrefix.Length..], out secret);
|
||||
}
|
||||
|
||||
string? encoded = Environment.GetEnvironmentVariable(reference[Prefix.Length..]);
|
||||
if (reference.StartsWith(FilePrefix, StringComparison.Ordinal)
|
||||
&& reference.Length > FilePrefix.Length)
|
||||
{
|
||||
return TryGetFileSecret(reference[FilePrefix.Length..], out secret);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryGetEnvironmentSecret(string variableName, out SecretMaterial? secret)
|
||||
{
|
||||
secret = null;
|
||||
string? encoded = Environment.GetEnvironmentVariable(variableName);
|
||||
if (string.IsNullOrEmpty(encoded))
|
||||
{
|
||||
return false;
|
||||
@@ -60,6 +74,12 @@ internal sealed class EnvironmentSecretProvider : ISecretProvider
|
||||
try
|
||||
{
|
||||
byte[] bytes = Convert.FromBase64String(encoded);
|
||||
if (bytes.Length is 0 or > MaximumSecretBytes)
|
||||
{
|
||||
CryptographicOperations.ZeroMemory(bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
secret = new SecretMaterial(bytes);
|
||||
CryptographicOperations.ZeroMemory(bytes);
|
||||
return true;
|
||||
@@ -69,6 +89,47 @@ internal sealed class EnvironmentSecretProvider : ISecretProvider
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetFileSecret(string path, out SecretMaterial? secret)
|
||||
{
|
||||
secret = null;
|
||||
byte[]? bytes = null;
|
||||
try
|
||||
{
|
||||
FileInfo file = new(path);
|
||||
if (!file.Exists
|
||||
|| !Path.IsPathFullyQualified(path)
|
||||
|| file.LinkTarget is not null
|
||||
|| file.Length is <= 0 or > MaximumSecretBytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes = File.ReadAllBytes(path);
|
||||
if (bytes.Length is 0 or > MaximumSecretBytes)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
secret = new SecretMaterial(bytes);
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception) when (exception is IOException
|
||||
or UnauthorizedAccessException
|
||||
or ArgumentException
|
||||
or NotSupportedException
|
||||
or System.Security.SecurityException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (bytes is not null)
|
||||
{
|
||||
CryptographicOperations.ZeroMemory(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class EphemeralDevelopmentSecretProvider : ISecretProvider, IDisposable
|
||||
|
||||
Reference in New Issue
Block a user