diff --git a/.github/workflows/UploadDockerImage.yml b/.github/workflows/UploadDockerImage.yml new file mode 100644 index 000000000..ba0699df6 --- /dev/null +++ b/.github/workflows/UploadDockerImage.yml @@ -0,0 +1,44 @@ +# Pushes Docker images created from the deploy tool's Dockerfile templates to an internal ECR so that they can be scanned for security vulnerabilities. +name: Upload Docker Images + +on: + # Manually trigger on specific branches + workflow_dispatch: + push: + branches: + - main + +permissions: + id-token: write + +jobs: + upload-docker-images: + runs-on: ubuntu-latest + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@8c3f20df09ac63af7b3ae3d7c91f105f857d8497 #v4 + with: + aws-region: us-west-2 + role-to-assume: ${{ secrets.DOCKER_IMAGE_UPLOADER_ROLE }} + role-duration-seconds: 1800 + + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET Core 6.0 + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + + - name: Restore dependencies + run: dotnet restore + + - name: Build + run: dotnet build --no-restore + + - name: Run Docker Image Uploader + run: | + cd ./test/AWS.Deploy.DockerImageUploader + dotnet run --project ./AWS.Deploy.DockerImageUploader.csproj \ No newline at end of file diff --git a/AWS.Deploy.sln b/AWS.Deploy.sln index 6540ad553..0c96ba215 100644 --- a/AWS.Deploy.sln +++ b/AWS.Deploy.sln @@ -67,6 +67,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWS.Deploy.DocGenerator", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWS.Deploy.DocGenerator.UnitTests", "test\AWS.Deploy.DocGenerator.UnitTests\AWS.Deploy.DocGenerator.UnitTests.csproj", "{7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AWS.Deploy.DockerImageUploader", "test\AWS.Deploy.DockerImageUploader\AWS.Deploy.DockerImageUploader.csproj", "{49A1C020-F4C8-4B28-A6B2-6AD3C8452E69}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -173,6 +175,10 @@ Global {7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}.Debug|Any CPU.Build.0 = Debug|Any CPU {7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}.Release|Any CPU.ActiveCfg = Release|Any CPU {7E661545-7DFD-4FE3-A5F9-767FAE30DFFE}.Release|Any CPU.Build.0 = Release|Any CPU + {49A1C020-F4C8-4B28-A6B2-6AD3C8452E69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {49A1C020-F4C8-4B28-A6B2-6AD3C8452E69}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49A1C020-F4C8-4B28-A6B2-6AD3C8452E69}.Release|Any CPU.ActiveCfg = Release|Any CPU + {49A1C020-F4C8-4B28-A6B2-6AD3C8452E69}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -204,6 +210,7 @@ Global {CEEBEC39-40E5-4A9B-878A-6EDB52B9B43E} = {C3A0C716-BDEA-4393-B223-AF8F8531522A} {6D4BD0C2-C2A0-4AFB-BC22-623DD64A4F84} = {11C7056E-93C1-408B-BD87-5270595BBE0E} {7E661545-7DFD-4FE3-A5F9-767FAE30DFFE} = {BD466B5C-D8B0-4069-98A9-6DC8F01FA757} + {49A1C020-F4C8-4B28-A6B2-6AD3C8452E69} = {BD466B5C-D8B0-4069-98A9-6DC8F01FA757} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5A4B2863-1763-4496-B122-651A38A4F5D7} diff --git a/test/AWS.Deploy.DockerImageUploader/AWS.Deploy.DockerImageUploader.csproj b/test/AWS.Deploy.DockerImageUploader/AWS.Deploy.DockerImageUploader.csproj new file mode 100644 index 000000000..91eb733db --- /dev/null +++ b/test/AWS.Deploy.DockerImageUploader/AWS.Deploy.DockerImageUploader.csproj @@ -0,0 +1,13 @@ + + + + Exe + net6.0 + enable + + + + + + + diff --git a/test/AWS.Deploy.DockerImageUploader/App.cs b/test/AWS.Deploy.DockerImageUploader/App.cs new file mode 100644 index 000000000..ac4ee7aa6 --- /dev/null +++ b/test/AWS.Deploy.DockerImageUploader/App.cs @@ -0,0 +1,78 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using AWS.Deploy.Common.IO; +using AWS.Deploy.Common; +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; +using System.Collections.Generic; +using System; +using System.Threading.Tasks; +using System.IO; + +namespace AWS.Deploy.DockerImageUploader +{ + /// + /// This serves as the dependency injection container for the console application. + /// + public class App + { + private readonly IFileManager _fileManager; + private readonly IDirectoryManager _directoryManager; + private readonly IProjectDefinitionParser _projectDefinitionParser; + private readonly CLI.App _deployToolCli; + + private readonly List _testApps = new() { "WebApiNET6", "ConsoleAppTask" }; + + public App(IServiceProvider serviceProvider) + { + _projectDefinitionParser = serviceProvider.GetRequiredService(); + _fileManager = serviceProvider.GetRequiredService(); + _directoryManager = serviceProvider.GetRequiredService(); + _deployToolCli = serviceProvider.GetRequiredService(); + } + + /// + /// Generates Dockerfiles for test applications using + /// the Dockerfile template. + /// It will then build and push the images to Amazon ECR where they are continuously scanned for security vulnerabilities. + /// + public async Task Run() + { + foreach (var testApp in _testApps) + { + var projectPath = ResolvePath(testApp); + await CreateImageAndPushToECR(projectPath); + } + } + + private async Task CreateImageAndPushToECR(string projectPath) + { + var projectDefinition = await _projectDefinitionParser.Parse(projectPath); + + var dockerEngine = new DockerEngine.DockerEngine(projectDefinition, _fileManager, _directoryManager); + dockerEngine.GenerateDockerFile(); + + var configFilePath = Path.Combine(projectPath, "DockerImageUploaderConfigFile.json"); + var deployArgs = new[] { "deploy", "--project-path", projectPath, "--diagnostics", "--apply", configFilePath, "--silent" }; + await _deployToolCli.Run(deployArgs); + } + + private string ResolvePath(string projectName) + { + const string testDir = "test"; + var testDirPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + while (testDirPath != null && !string.Equals(new DirectoryInfo(testDirPath).Name, testDir, StringComparison.OrdinalIgnoreCase)) + { + testDirPath = Directory.GetParent(testDirPath)?.FullName; + } + + if (string.IsNullOrEmpty(testDirPath)) + { + throw new Exception($"Failed to find path to '{testDir}' directory."); + } + + return Path.Combine(testDirPath, "..", "testapps", projectName); + } + } +} diff --git a/test/AWS.Deploy.DockerImageUploader/Program.cs b/test/AWS.Deploy.DockerImageUploader/Program.cs new file mode 100644 index 000000000..695792c57 --- /dev/null +++ b/test/AWS.Deploy.DockerImageUploader/Program.cs @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +using Microsoft.Extensions.DependencyInjection; +using AWS.Deploy.CLI.Extensions; +using System.Threading.Tasks; +using System; + +namespace AWS.Deploy.DockerImageUploader +{ + /// + /// This console app generates a docker file for a .NET console application and a web application via + /// the Dockerfile template. + /// It will then build and push the images to Amazon ECR where they are continuously scanned for security vulnerabilities. + /// + internal class Program + { + public static async Task Main(string[] args) + { + var serviceCollection = new ServiceCollection(); + + serviceCollection.AddCustomServices(); + serviceCollection.AddSingleton(); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + var app = serviceProvider.GetService(); + if (app == null) + { + throw new Exception("App dependencies aren't injected correctly." + + " Verify that all the required dependencies to instantiate DockerImageUploader are present."); + } + + await app.Run(); + } + } +} diff --git a/testapps/ConsoleAppTask/DockerImageUploaderConfigFile.json b/testapps/ConsoleAppTask/DockerImageUploaderConfigFile.json new file mode 100644 index 000000000..fcc40ce0e --- /dev/null +++ b/testapps/ConsoleAppTask/DockerImageUploaderConfigFile.json @@ -0,0 +1,7 @@ +{ + "RecipeId": "PushContainerImageEcr", + "settings": { + "ImageTag": "latest", + "ECRRepositoryName": "deploytool-consoleapp" + } +} diff --git a/testapps/WebApiNET6/DockerImageUploaderConfigFile.json b/testapps/WebApiNET6/DockerImageUploaderConfigFile.json new file mode 100644 index 000000000..51d813572 --- /dev/null +++ b/testapps/WebApiNET6/DockerImageUploaderConfigFile.json @@ -0,0 +1,7 @@ +{ + "RecipeId": "PushContainerImageEcr", + "settings": { + "ImageTag": "latest", + "ECRRepositoryName": "deploytool-webapp" + } +}