feat(deployment): introduce 'use_build_secrets' setting for enhanced security during Docker builds and update related logic in deployment process
This commit is contained in:
@@ -361,6 +361,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private function detectBuildKitCapabilities(): void
|
||||
{
|
||||
// If build secrets are not enabled, skip detection and use traditional args
|
||||
if (! $this->application->settings->use_build_secrets) {
|
||||
$this->dockerBuildkitSupported = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$serverToCheck = $this->use_build_server ? $this->build_server : $this->server;
|
||||
$serverName = $this->use_build_server ? "build server ({$serverToCheck->name})" : "deployment server ({$serverToCheck->name})";
|
||||
|
||||
@@ -376,7 +383,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
if ($majorVersion < 18 || ($majorVersion == 18 && $minorVersion < 9)) {
|
||||
$this->dockerBuildkitSupported = false;
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} on {$serverName} does not support BuildKit (requires 18.09+). Using traditional build arguments.");
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} on {$serverName} does not support BuildKit (requires 18.09+). Build secrets feature disabled.");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -395,11 +402,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if (trim($buildkitTest) === 'supported') {
|
||||
$this->dockerBuildkitSupported = true;
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} with BuildKit secrets support detected on {$serverName}.");
|
||||
$this->application_deployment_queue->addLogEntry('✓ Build secrets will be used for enhanced security during builds.');
|
||||
$this->application_deployment_queue->addLogEntry('Build secrets are enabled and will be used for enhanced security.');
|
||||
} else {
|
||||
$this->dockerBuildkitSupported = false;
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} on {$serverName} does not have BuildKit secrets support enabled.");
|
||||
$this->application_deployment_queue->addLogEntry('⚠ Using traditional build arguments (less secure but compatible).');
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} on {$serverName} does not have BuildKit secrets support.");
|
||||
$this->application_deployment_queue->addLogEntry('Build secrets feature is enabled but not supported. Using traditional build arguments.');
|
||||
}
|
||||
} else {
|
||||
// Buildx is available, which means BuildKit is available
|
||||
@@ -412,17 +419,17 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if (trim($secretsTest) === 'supported') {
|
||||
$this->dockerBuildkitSupported = true;
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} with BuildKit and Buildx detected on {$serverName}.");
|
||||
$this->application_deployment_queue->addLogEntry('✓ Build secrets will be used for enhanced security during builds.');
|
||||
$this->application_deployment_queue->addLogEntry('Build secrets are enabled and will be used for enhanced security.');
|
||||
} else {
|
||||
$this->dockerBuildkitSupported = false;
|
||||
$this->application_deployment_queue->addLogEntry("Docker {$dockerVersion} with Buildx on {$serverName}, but secrets not supported.");
|
||||
$this->application_deployment_queue->addLogEntry('⚠ Using traditional build arguments (less secure but compatible).');
|
||||
$this->application_deployment_queue->addLogEntry('Build secrets feature is enabled but not supported. Using traditional build arguments.');
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->dockerBuildkitSupported = false;
|
||||
$this->application_deployment_queue->addLogEntry("Could not detect BuildKit capabilities on {$serverName}: {$e->getMessage()}");
|
||||
$this->application_deployment_queue->addLogEntry('⚠ Using traditional build arguments as fallback.');
|
||||
$this->application_deployment_queue->addLogEntry('Build secrets feature is enabled but detection failed. Using traditional build arguments.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,7 +562,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->generate_image_names();
|
||||
$this->cleanup_git();
|
||||
|
||||
$this->detectBuildKitCapabilities();
|
||||
$this->generate_build_env_variables();
|
||||
|
||||
$this->application->loadComposeFile(isInit: false);
|
||||
@@ -566,7 +572,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
// For raw compose, we cannot automatically add secrets configuration
|
||||
// User must define it manually in their docker-compose file
|
||||
if ($this->dockerBuildkitSupported && ! empty($this->build_secrets)) {
|
||||
if ($this->application->settings->use_build_secrets && $this->dockerBuildkitSupported && ! empty($this->build_secrets)) {
|
||||
$this->application_deployment_queue->addLogEntry('Build secrets are configured. Ensure your docker-compose file includes build.secrets configuration for services that need them.');
|
||||
}
|
||||
} else {
|
||||
@@ -588,8 +594,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
return;
|
||||
}
|
||||
|
||||
// Add build secrets to compose file if BuildKit is supported
|
||||
if ($this->dockerBuildkitSupported && ! empty($this->build_secrets)) {
|
||||
// Add build secrets to compose file if enabled and BuildKit is supported
|
||||
if ($this->application->settings->use_build_secrets && $this->dockerBuildkitSupported && ! empty($this->build_secrets)) {
|
||||
$composeFile = $this->add_build_secrets_to_compose($composeFile);
|
||||
}
|
||||
|
||||
@@ -716,7 +722,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->dockerfile_location = $this->application->dockerfile_location;
|
||||
}
|
||||
$this->prepare_builder_image();
|
||||
$this->detectBuildKitCapabilities();
|
||||
$this->check_git_if_build_needed();
|
||||
$this->generate_image_names();
|
||||
$this->clone_repository();
|
||||
@@ -2336,11 +2341,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
executeInDocker($this->deployment_uuid, "cat {$this->workdir}/.nixpacks/Dockerfile"),
|
||||
'hidden' => true,
|
||||
]);
|
||||
if ($this->dockerBuildkitSupported) {
|
||||
if ($this->dockerBuildkitSupported && $this->application->settings->use_build_secrets) {
|
||||
// Modify the nixpacks Dockerfile to use build secrets
|
||||
$this->modify_nixpacks_dockerfile_for_secrets("{$this->workdir}/.nixpacks/Dockerfile");
|
||||
$secrets_flags = $this->build_secrets ? " {$this->build_secrets}" : '';
|
||||
$build_command = "DOCKER_BUILDKIT=1 docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile{$secrets_flags} --progress plain -t {$this->build_image_name} {$this->workdir}";
|
||||
} elseif ($this->dockerBuildkitSupported) {
|
||||
// BuildKit without secrets
|
||||
$build_command = "DOCKER_BUILDKIT=1 docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile --progress plain -t {$this->build_image_name} {$this->build_args} {$this->workdir}";
|
||||
} else {
|
||||
$build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile --progress plain -t {$this->build_image_name} {$this->build_args} {$this->workdir}";
|
||||
}
|
||||
@@ -2649,10 +2657,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
$variables = collect([])->merge($this->env_args);
|
||||
}
|
||||
|
||||
if ($this->dockerBuildkitSupported) {
|
||||
// Check if build secrets are enabled and BuildKit is supported
|
||||
if ($this->dockerBuildkitSupported && $this->application->settings->use_build_secrets) {
|
||||
$this->generate_build_secrets($variables);
|
||||
$this->build_args = '';
|
||||
} else {
|
||||
// Fall back to traditional build args
|
||||
$this->build_args = $variables->map(function ($value, $key) {
|
||||
$value = escapeshellarg($value);
|
||||
|
||||
@@ -2663,6 +2673,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
|
||||
private function generate_docker_env_flags_for_secrets()
|
||||
{
|
||||
// Only generate env flags if build secrets are enabled
|
||||
if (! $this->application->settings->use_build_secrets) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$variables = $this->pull_request_id === 0
|
||||
? $this->application->environment_variables()->where('key', 'not like', 'NIXPACKS_%')->get()
|
||||
: $this->application->environment_variables_preview()->where('key', 'not like', 'NIXPACKS_%')->get();
|
||||
@@ -2737,8 +2752,8 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
|
||||
private function modify_nixpacks_dockerfile_for_secrets($dockerfile_path)
|
||||
{
|
||||
// Only process if we have secrets to mount
|
||||
if (empty($this->build_secrets)) {
|
||||
// Only process if build secrets are enabled and we have secrets to mount
|
||||
if (! $this->application->settings->use_build_secrets || empty($this->build_secrets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,8 @@ class All extends Component
|
||||
|
||||
public bool $is_env_sorting_enabled = false;
|
||||
|
||||
public bool $use_build_secrets = false;
|
||||
|
||||
protected $listeners = [
|
||||
'saveKey' => 'submit',
|
||||
'refreshEnvs',
|
||||
@@ -34,6 +36,7 @@ class All extends Component
|
||||
public function mount()
|
||||
{
|
||||
$this->is_env_sorting_enabled = data_get($this->resource, 'settings.is_env_sorting_enabled', false);
|
||||
$this->use_build_secrets = data_get($this->resource, 'settings.use_build_secrets', false);
|
||||
$this->resourceClass = get_class($this->resource);
|
||||
$resourceWithPreviews = [\App\Models\Application::class];
|
||||
$simpleDockerfile = filled(data_get($this->resource, 'dockerfile'));
|
||||
@@ -49,6 +52,7 @@ class All extends Component
|
||||
$this->authorize('manageEnvironment', $this->resource);
|
||||
|
||||
$this->resource->settings->is_env_sorting_enabled = $this->is_env_sorting_enabled;
|
||||
$this->resource->settings->use_build_secrets = $this->use_build_secrets;
|
||||
$this->resource->settings->save();
|
||||
$this->getDevView();
|
||||
$this->dispatch('success', 'Environment variable settings updated.');
|
||||
|
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('application_settings', function (Blueprint $table) {
|
||||
$table->boolean('use_build_secrets')->default(false)->after('is_build_server_enabled');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('application_settings', function (Blueprint $table) {
|
||||
$table->dropColumn('use_build_secrets');
|
||||
});
|
||||
}
|
||||
};
|
@@ -13,17 +13,32 @@
|
||||
@endcan
|
||||
</div>
|
||||
<div>Environment variables (secrets) for this resource. </div>
|
||||
@if ($resourceClass === 'App\Models\Application' && data_get($resource, 'build_pack') !== 'dockercompose')
|
||||
<div class="w-64 pt-2">
|
||||
@can('manageEnvironment', $resource)
|
||||
<x-forms.checkbox id="is_env_sorting_enabled" label="Sort alphabetically"
|
||||
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order (like you pasted them or in the order you created them)."
|
||||
instantSave></x-forms.checkbox>
|
||||
@else
|
||||
<x-forms.checkbox id="is_env_sorting_enabled" label="Sort alphabetically"
|
||||
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order (like you pasted them or in the order you created them)."
|
||||
disabled></x-forms.checkbox>
|
||||
@endcan
|
||||
@if ($resourceClass === 'App\Models\Application')
|
||||
<div class="flex flex-col gap-2 pt-2">
|
||||
@if (data_get($resource, 'build_pack') !== 'dockercompose')
|
||||
<div class="w-64">
|
||||
@can('manageEnvironment', $resource)
|
||||
<x-forms.checkbox id="is_env_sorting_enabled" label="Sort alphabetically"
|
||||
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order (like you pasted them or in the order you created them)."
|
||||
instantSave></x-forms.checkbox>
|
||||
@else
|
||||
<x-forms.checkbox id="is_env_sorting_enabled" label="Sort alphabetically"
|
||||
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order (like you pasted them or in the order you created them)."
|
||||
disabled></x-forms.checkbox>
|
||||
@endcan
|
||||
</div>
|
||||
@endif
|
||||
<div class="w-64">
|
||||
@can('manageEnvironment', $resource)
|
||||
<x-forms.checkbox id="use_build_secrets" label="Use Docker Build Secrets"
|
||||
helper="Enable Docker BuildKit secrets for enhanced security during builds. Secrets won't be exposed in the final image. Requires Docker 18.09+ with BuildKit support."
|
||||
instantSave></x-forms.checkbox>
|
||||
@else
|
||||
<x-forms.checkbox id="use_build_secrets" label="Use Docker Build Secrets"
|
||||
helper="Enable Docker BuildKit secrets for enhanced security during builds. Secrets won't be exposed in the final image. Requires Docker 18.09+ with BuildKit support."
|
||||
disabled></x-forms.checkbox>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@if ($resource->type() === 'service' || $resource?->build_pack === 'dockercompose')
|
||||
|
Reference in New Issue
Block a user