자바 DockerSandbox 라이브러리

14013 단어 javasandboxdocker
GitHub: https://github.com/edwardUL99/DockerSandbox

DockerSandbox라는 Apache 2.0 라이선스로 작업한 오픈 소스 라이브러리를 소개하려고 합니다. 컨테이너화된 샌드박스 환경에서 코드를 실행할 수 있도록 하는 Docker Java 클라이언트https://github.com/docker-java/docker-java에 래퍼 API를 제공합니다. StepikOrg가 https://github.com/StepicOrg/epicbox에서 epicbox와 함께 Python에 제공하는 것과 유사한 Java용 기능을 제공합니다.

사용하기 쉬운 Java용 API를 제공하여 가능한 한 자세한 내용을 적게 하는 것을 목표로 합니다. 설정해야 하는 모든 것은 샌드박스로 지정하려는 언어를 실행할 수 있는 Docker 이미지입니다. 이 게시물은 API의 초기 안정 릴리스와 이를 사용하는 방법의 예를 설명합니다.

사용 사례



원격 코드 제출 서버(예: Replit)와 같은 다른 소스에서 수신할 수 있는 신뢰할 수 없는 코드를 실행하려고 한다고 가정합니다. 이 코드를 수락하는 서버는 단순히 하위 프로세스를 가동하여 코드를 실행할 수 있습니다. 그러나 여기에는 다음과 같은 보안 위험이 있습니다.
  • 파일 삭제
  • 악성코드 제출
  • 맬웨어
  • 기타

  • Docker는 여전히 코드 실행 측면에서 가장 안전하지 않지만(여전히 취약성이 있고 훨씬 더 높은 오버헤드가 있는 가상 머신 경로를 사용할 수 있음) 라이브러리는 컨테이너에서 최소 권한을 가진 사용자의 설정을 지시하여 몇 가지 예방 조치를 취합니다. sandbox라는 프로필(나중에 자세히 설명)을 통해 사용됩니다. Docker 컨테이너의 네트워크도 비활성화할 수 있습니다.

    이 라이브러리를 사용하면 코드를 실행할 때마다 Docker 컨테이너를 스핀업할 수 있으므로 코드가 컨테이너 내부에서 악의적인 작업을 수행하더라도 코드 실행이 완료되면 컨테이너가 파괴됩니다. 이 프로세스를 더 쉽게 만들기 위해 Docker Java 클라이언트 라이브러리에 추상화 계층을 추가합니다.

    예시



    다음은 루트 사용자를 사용하여 프로그램을 컴파일한 다음 사용된 샌드박스를 사용하여 gcc_run 프로필을 사용하여 프로그램을 실행하는 gcc_compile 프로필을 사용하여 C 프로그램을 컴파일하는 데 사용되는 라이브러리의 예입니다.

    package io.github.edwardUL99.docker.sandbox;
    
    import io.github.edwardUL99.docker.sandbox.api.Docker;
    import io.github.edwardUL99.docker.sandbox.api.DockerSandbox;
    import io.github.edwardUL99.docker.sandbox.api.components.Result;
    import io.github.edwardUL99.docker.sandbox.api.components.WorkingDirectory;
    
    public class Example {
        public static void main(String[] args) {
            DockerSandbox sandbox = DockerSandbox.builder()
                            .withJson("profiles.json") // see profiles.json in the root of the project for the example file
                    // Or you can do withShellProfiles(Docker.Shell.SH or Docker.Shell.BASH, profiles)
                            .withBinding("/path/to/local:/path/to/remote")
                            .withEnvironmentVariables("VAR1=VALUE1", "VAR2=VALUE2")
                            .build();
    
            sandbox.start("/home/sandbox");
    
            try {
                Docker.Command command = new Docker.Command("gcc main.c -o main");
                Result result = sandbox.run("gcc_compile", command,
                        new WorkingDirectory.UploadedFile("main.c", "/path/to/main.c"));
    
                // do something with result
    
                command = new Docker.Command("./main");
                result = sandbox.run("gcc_run", command, "Stdin Input"); // notice how this run command uses the compiled file from the previous execution
                // but you don't have to re-upload it as generated files from the previous call
                // are shared
    
                // do something with result
    
                // the call to finish in the finally block will free any resources such as created files on the host machine in the working directory
            } catch (Exception ex) {
                ex.printStackTrace();
                sandbox.cleanup(); // clean up any created containers that didn't get removed
            } finally {
                sandbox.finish(); // ensure all resources are freed
            }
        }
    }
    

    sandbox.cleanup()에 대한 호출은 예외가 발생하는 경우 매달린 컨테이너가 모두 지워지도록 합니다. sandbox.finish()는 생성된 컨테이너가 해체되도록 하기 위해 finally 블록에 배치됩니다. gcc_rungcc_compile 프로필은 여기에서 볼 수 있습니다.

    {
       "name": "gcc_compile",
       "image": "gcc-docker",
       "container-name": "gcc-docker",
       "user": "root",
       "networkDisabled": true
    },
    {
       "name": "gcc_run",
       "image": "gcc-docker",
       "container-name": "gcc-docker",
       "user": "sandbox",
       "networkDisabled": true
    }
    

    sandbox.start("/home/sandbox")에 대한 호출은 gcc_compile 실행에서 생성된 파일을 gcc_run 실행에서 생성된 컨테이너와 공유할 수 있도록 샌드박스에 작업 디렉토리 마운트를 설정합니다. 즉, 여기서 컴파일 출력은 실행 컨테이너에서 실행됩니다.

    설정



    라이브러리를 설정하려면 1개 이상Profile을 정의해야 합니다. 프로필에는 sandbox.run 호출에 전달되는 프로필의 이름, Docker 이미지의 이름, 가동 컨테이너에 부여할 이름, 명령을 실행할 사용자, 마지막으로 네트워크를 활성화/비활성화하는 사용자가 포함됩니다. 컨테이너에 대한 연결성.

    이러한 프로필은 다음 구조의 JSON 파일에서 정의할 수 있습니다.

    {
      "profiles": [
        ... profiles go here
      ],
      "docker_host": "unix:///var/run/docker.sock",
      "shell": "bash"
    }
    


    또한 Docker 컨테이너에서 실행할 Docker 엔진 및 셸의 호스트를 구성합니다. 구성 시 JSON 파일의 경로를 샌드박스 빌더에 전달합니다. 샘플profiles.json 및 샘플 이미지는 GitHub 리포지토리에서 제공됩니다.

    프로필과 셸은 다음과 같이 프로그래밍 방식으로 구성할 수도 있습니다.

    dockerSandbox = DockerSandbox.builder()
                    .withShellProfiles(Docker.Shell.BASH, new Profile("java_run", "java-docker", "java-docker", "sandbox"),
                            new Profile("java_compile", "java-docker", "java-docker", "root"),
                            new Profile("gcc_run", "gcc-docker", "gcc-docker", "sandbox"),
                            new Profile("gcc_compile", "gcc-docker", "gcc-docker", "root"))
                    .withEnvironmentVariables("VAR1=VALUE1", "VAR2=VALUE2", "VAR3=VALUE3")
                    .build();
    


    다운로드



    다음 좌표에서 Maven을 사용하여 라이브러리를 다운로드할 수 있습니다.

    <artifactId>io.github.edwardUL99</artifactId>
    <groupId>docker-sandbox</groupId>
    <version>1.0.0</version>
    


    감사합니다



    시간을 내어 이 게시물을 읽어주셔서 감사합니다. 도서관이 누군가에게 도움이 되었으면 합니다. 기능 요청이 있거나 버그를 발견하면 GitHub 리포지토리에 보고할 수 있습니다 :)

    좋은 웹페이지 즐겨찾기