From a8b8bf1e318444e1e74bc77fcfba42db1e2a4989 Mon Sep 17 00:00:00 2001 From: maafk Date: Thu, 2 Sep 2021 05:14:11 -0400 Subject: [PATCH] fix(core): allow asset bundling when selinux is enabled (#15742) ---- Revisiting [#9445](https://github.com/aws/aws-cdk/pull/9445) but looking to see if running on linux with selinux enabled. This PR aims to allow for asset bundling on linux os with selinux enabled *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/core/lib/bundling.ts | 27 +++- packages/@aws-cdk/core/test/bundling.test.ts | 134 ++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/packages/@aws-cdk/core/lib/bundling.ts b/packages/@aws-cdk/core/lib/bundling.ts index c6b6b66881771..1ce4633354511 100644 --- a/packages/@aws-cdk/core/lib/bundling.ts +++ b/packages/@aws-cdk/core/lib/bundling.ts @@ -200,7 +200,7 @@ export class BundlingDockerImage { ...options.user ? ['-u', options.user] : [], - ...flatten(volumes.map(v => ['-v', `${v.hostPath}:${v.containerPath}:${v.consistency ?? DockerVolumeConsistency.DELEGATED}`])), + ...flatten(volumes.map(v => ['-v', `${v.hostPath}:${v.containerPath}:${isSeLinux() ? 'z,' : ''}${v.consistency ?? DockerVolumeConsistency.DELEGATED}`])), ...flatten(Object.entries(environment).map(([k, v]) => ['--env', `${k}=${v}`])), ...options.workingDirectory ? ['-w', options.workingDirectory] @@ -481,3 +481,28 @@ function dockerExec(args: string[], options?: SpawnSyncOptions) { return proc; } + +function isSeLinux() : boolean { + if (process.platform != 'linux') { + return false; + } + const prog = 'selinuxenabled'; + const proc = spawnSync(prog, [], { + stdio: [ // show selinux status output + 'pipe', // get value of stdio + process.stderr, // redirect stdout to stderr + 'inherit', // inherit stderr + ], + }); + if (proc.error) { + // selinuxenabled not a valid command, therefore not enabled + return false; + } + if (proc.status == 0) { + // selinux enabled + return true; + } else { + // selinux not enabled + return false; + } +} diff --git a/packages/@aws-cdk/core/test/bundling.test.ts b/packages/@aws-cdk/core/test/bundling.test.ts index 174bc15c7b115..48522347e698c 100644 --- a/packages/@aws-cdk/core/test/bundling.test.ts +++ b/packages/@aws-cdk/core/test/bundling.test.ts @@ -12,6 +12,7 @@ nodeunitShim({ }, 'bundling with image from registry'(test: Test) { + sinon.stub(process, 'platform').value('darwin'); const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({ status: 0, stderr: Buffer.from('stderr'), @@ -230,6 +231,7 @@ nodeunitShim({ }, 'custom entrypoint is passed through to docker exec'(test: Test) { + sinon.stub(process, 'platform').value('darwin'); const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({ status: 0, stderr: Buffer.from('stderr'), @@ -343,7 +345,9 @@ nodeunitShim({ test.done(); }, - 'adding user provided securit-opt'(test: Test) { + 'adding user provided security-opt'(test: Test) { + // GIVEN + sinon.stub(process, 'platform').value('darwin'); const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({ status: 0, stderr: Buffer.from('stderr'), @@ -352,8 +356,9 @@ nodeunitShim({ output: ['stdout', 'stderr'], signal: null, }); - const image = DockerImage.fromRegistry('alpine'); + + // GIVEN image.run({ command: ['cool', 'command'], environment: { @@ -379,4 +384,129 @@ nodeunitShim({ ], { stdio: ['ignore', process.stderr, 'inherit'] })); test.done(); }, + + 'ensure selinux docker mount'(test: Test) { + // GIVEN + sinon.stub(process, 'platform').value('linux'); + const spawnSyncStub = sinon.stub(child_process, 'spawnSync'); + spawnSyncStub.onFirstCall().returns({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['selinuxenable-command', 'stderr'], + signal: null, + }); + spawnSyncStub.onSecondCall().returns({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 124, + output: ['docker run command', 'stderr'], + signal: null, + }); + + // WHEN + const image = DockerImage.fromRegistry('alpine'); + image.run({ + command: ['cool', 'command'], + volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }], + workingDirectory: '/working-directory', + user: 'user:group', + }); + + // THEN + test.ok(spawnSyncStub.secondCall.calledWith('docker', [ + 'run', '--rm', + '-u', 'user:group', + '-v', '/host-path:/container-path:z,delegated', + '-w', '/working-directory', + 'alpine', + 'cool', 'command', + ], { stdio: ['ignore', process.stderr, 'inherit'] })); + test.done(); + }, + + 'ensure selinux docker mount on linux with selinux disabled'(test: Test) { + // GIVEN + sinon.stub(process, 'platform').value('linux'); + const spawnSyncStub = sinon.stub(child_process, 'spawnSync'); + spawnSyncStub.onFirstCall().returns({ + status: 1, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['selinuxenabled output', 'stderr'], + signal: null, + }); + spawnSyncStub.onSecondCall().returns({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 124, + output: ['docker run command', 'stderr'], + signal: null, + }); + + // WHEN + const image = DockerImage.fromRegistry('alpine'); + image.run({ + command: ['cool', 'command'], + volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }], + workingDirectory: '/working-directory', + user: 'user:group', + }); + + // THEN + test.ok(spawnSyncStub.secondCall.calledWith('docker', [ + 'run', '--rm', + '-u', 'user:group', + '-v', '/host-path:/container-path:delegated', + '-w', '/working-directory', + 'alpine', + 'cool', 'command', + ], { stdio: ['ignore', process.stderr, 'inherit'] })); + test.done(); + }, + 'ensure no selinux docker mount if selinuxenabled isn\'t an available command'(test: Test) { + // GIVEN + sinon.stub(process, 'platform').value('linux'); + const spawnSyncStub = sinon.stub(child_process, 'spawnSync'); + spawnSyncStub.onFirstCall().returns({ + status: 127, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 123, + output: ['selinuxenabled output', 'stderr'], + signal: null, + }); + spawnSyncStub.onSecondCall().returns({ + status: 0, + stderr: Buffer.from('stderr'), + stdout: Buffer.from('stdout'), + pid: 124, + output: ['docker run command', 'stderr'], + signal: null, + }); + + // WHEN + const image = DockerImage.fromRegistry('alpine'); + image.run({ + command: ['cool', 'command'], + volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }], + workingDirectory: '/working-directory', + user: 'user:group', + }); + + // THEN + test.ok(spawnSyncStub.secondCall.calledWith('docker', [ + 'run', '--rm', + '-u', 'user:group', + '-v', '/host-path:/container-path:delegated', + '-w', '/working-directory', + 'alpine', + 'cool', 'command', + ], { stdio: ['ignore', process.stderr, 'inherit'] })); + test.done(); + }, });