Recently spent a few days connecting dots and solving this puzzle about how to execute scripts on host system in docker.

This is not secure and this is not how you use docker! However, this simplifies deployment and integrates well into existing infrastructure.

 

C# application code

using System.Diagnostics;

namespace ConsoleApp
{
    public class Program
    {
        static void Main()
        {
            ExecuteShell("nsenter -t 1 -m -u -n -i sh /var/nfs/scripts/test.sh");
        }

        private static string ExecuteShell(string command)
        {
            var escapedArgs = command.Replace("\"", "\\\"");

            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "/bin/sh",
                    Arguments = $"-c \"{escapedArgs}\"",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                }
            };
            process.Start();
            string result = process.StandardOutput.ReadToEnd();
            process.WaitForExit();
            return result;
        }
    }
}

 

The most important part is this line:

nsenter -t 1 -m -u -n -i sh /var/nfs/scripts/test.sh

  • nsenter -t 1 -m -u -n -i sh - will create a new shell on the same process namespace as process 1.
  • /var/nfs/scripts/test.sh - shell script on the host system, which we want to execute.

When we combine these two parts we get - new shell console on the host and we execute a file that exists on the host while still being in docker.

 

Dockerfile

Well, you don't need anything modifications. Even visual studio generated dockerfile will do fine.

 

Start docker container

docker run --privileged --pid=host MyProjectImage

Two main arguments:

 

Now if we connect all the parts together:

  • --pid=host means our container will share the same process namespace with the host.
  • nsenter -t 1 will create a shell on the same namespace as a process with id 1, since we share namespace, the first process is from the host machine. We get a shell on the host machine.

How to test

ExecuteShell will always return an empty string. So the best way to test this out is simply by creating a script that writes some output to a new file, in my case I have a file /var/nfs/scripts/test.sh with the following content:

date > /tmp/date.txt

 

Check out my other projects
Active forks newsletter
Get a glimpse on open source active forks. Weekly newsletter with selection of repositories and their active forks.

Comments


Comments are closed