Permission denied while executing binaries in tmp folder (Docker) - docker

Hello I am trying to build an image which can compile and run a c++ program securely.
FROM golang:latest as builder
WORKDIR /app
COPY . .
RUN go mod download
RUN env CGO_ENABLED=0 go build -o /worker
FROM alpine:latest
RUN apk update && apk add --no-cache g++ && apk add --no-cache tzdata
ENV TZ=Asia/Kolkata
WORKDIR /
COPY --from=builder worker /bin
ARG USER=default
RUN addgroup -S $USER && adduser -S $USER -G $USER
USER $USER
ENTRYPOINT [ "worker" ]
version: "3.9"
services:
gpp:
build: .
environment:
- token=test_token
- code=#include <iostream>\r\n\r\nusing namespace std;\r\n\r\nint main() {\r\n int a = 10;\r\n int b = 20;\r\n cout << a << \" \" << b << endl;\r\n int temp = a;\r\n a = b;\r\n b = temp;\r\n cout << a << \" \" << b << endl;\r\n return 0;\r\n}
network_mode: bridge
privileged: false
read_only: true
tmpfs: /tmp
security_opt:
- "no-new-privileges"
cap_drop:
- "all"
Here worker is a golang binary which reads code from environment variable and stores it in /tmp folder as main.cpp, and then tries to compile and run it using g++ /tmp/main.cpp && ./tmp/a.out (using golang exec)
I am getting this error scratch_4-gpp-1 | Error : fork/exec /tmp/a.out: permission denied, from which what I can understand / know that executing anything from tmp directory is restricted.
Since, I am using read_only root file system, I can only work on tmp directory, Please guide me how I can achieve above task keeping my container secured.

Docker's default options for a tmpfs include noexec. docker run --tmpfs allows an extended set of mount options, but neither Compose tmpfs: nor the extended syntax of volumes: allows changing anything other than the size option.
One straightforward option here is to use an anonymous volume. Syntactically this looks like a normal volumes: line, except it only has a container path. The read_only: option will make the container's root filesystem be read-only, but volumes are exempted from this.
version: '3.8'
services:
...
read_only: true
volumes:
- /build # which will be read-write
This will be a "normal" Docker volume, so it will be disk-backed and you'll be able to see it in docker volume ls.

Complete summary of solution -
#davidmaze mentioned to add an anonymous volume using
version: '3.8'
services:
...
read_only: true
volumes:
- /build # which will be read-write
as I replied I am still getting an error Cannot create temporary file in ./: Read-only file system when I tried to compile my program. When I debugged my container to see file system changes in read_only:false mode, I found that compiler is trying to save the a.out file in /bin folder, which is suppose
to be read only.
So I added this additional line before the entry point and my issue was solved.
FROM golang:latest as builder
WORKDIR /app
COPY . .
RUN go mod download
RUN env CGO_ENABLED=0 go build -o /worker
FROM alpine:latest
RUN apk update && apk add --no-cache g++ && apk add --no-cache tzdata
ENV TZ=Asia/Kolkata
WORKDIR /
COPY --from=builder worker /bin
ARG USER=default
RUN addgroup -S $USER && adduser -S $USER -G $USER
USER $USER
WORKDIR /build <---- this line
ENTRYPOINT [ "worker" ]

Related

my-appname| /bin/sh: 1: /app/tmpmain.exe: not found | air

I'm facing an issue, am trying to run my go fiber project inside docker with air but am getting this error
uni-blog | /bin/sh: 1: /app/tmpmain.exe: not found
am using
Windows 11
Docker desktop
golang latest
air 1.27.10
fiber latest
Here is my docker compose and dockerfile
# docker-compose up -d --build
version: "3.8"
services:
app:
container_name: uni-blog
image: app-dev
build:
context: .
target: development
volumes:
- ./:/app
ports:
- 3000:3000
FROM golang:1.17 as development
RUN apt update && apt upgrade -y && \
apt install -y git \
make openssh-client
RUN curl -fLo install.sh https://raw.githubusercontent.com/cosmtrek/air/master/install.sh \
&& chmod +x install.sh && sh install.sh && cp ./bin/air /bin/air
RUN air -v
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
EXPOSE 3000
CMD air
I also tried installing air following the readME instructions still it gives me this error
Please help
Thanks in advance
The volumes: mount you have replaces the /app directory in the image with content from the host. If the binary is built in the Dockerfile, that volumes: mount hides it; if you don't have a matching compatible binary on the host in the same place, you'll get an error like what you see.
I'd remove that volumes: block so you're actually running the binary that's built into the image. The docker-compose.yml file can be reduced to as little as:
version: '3.8'
services:
app:
build: .
ports:
- '3000:3000'
If you look the error, you ca notice there is a typo between tmp/main.exe:
/bin/sh: 1: /app/tmpmain.exe: not found
This is coming from .air.toml config file:
bin = "tmp\\main.exe"
Create .air.toml file in project root like so:
root = "."
tmp_dir = "tmp"
[build]
# Build binary.
cmd = "go build -o ./tmp/main.exe ."
# Read binary.
bin = "tmp/main.exe"
# Watch changes in those files
include_ext = [ "go", "yml"]
# Ignore changes in these files
exclude_dir = ["tmp"]
# Stop builds from triggering too fast
delay = 1000 # ms
[misc]
clean_on_exit = true

COPY failed: forbidden path outside the build context docker compose [duplicate]

This question already has answers here:
How to include files outside of Docker's build context?
(19 answers)
Closed 1 year ago.
THis is the project structure
Project
/deployment
/Dockerfile
/docker-compose.yml
/services
/ui
/widget
Here is the docker file
FROM node:14
WORKDIR /app
USER root
# create new user (only root can do this) and assign owenership to newly created user
RUN echo "$(date '+%Y-%m-%d %H:%M:%S'): ======> Setup Appusr" \
&& groupadd -g 1001 appusr \
&& useradd -r -u 1001 -g appusr appusr \
&& mkdir /home/appusr/ \
&& chown -R appusr:appusr /home/appusr/\
&& chown -R appusr:appusr /app
# switch to new created user so that appuser will be responsible for all files and has access
USER appusr:appusr
COPY ../services/ui/widget/ /app/
COPY ../.env /app/
# installing deps
RUN npm install
and docker-compose
version: "3.4"
x-env: &env
HOST: 127.0.0.1
services:
widget:
build:
dockerfile: Dockerfile
context: .
ports:
- 3002:3002
command:
npm start
environment:
<<: *env
restart: always
and from project/deplyment/docker-compose up it shows
Step 6/8 : COPY ../services/ui/widget/ /app/
ERROR: Service 'widget' failed to build : COPY failed: forbidden path outside the build context: ../services/ui/widget/ ()
am i setting the wrong context?
You cannot COPY or ADD files outside the current path where Dockerfile exists.
You should either move these two directories to where Dockerfile is and then change your Dockerfile to:
COPY ./services/ui/widget/ /app/
COPY ./.env /app/
Or use volumes in docker-compose, and remove the two COPY lines.
So, your docker-compose should look like this:
x-env: &env
HOST: 127.0.0.1
services:
widget:
build:
dockerfile: Dockerfile
context: .
ports:
- 3002:3002
command:
npm start
environment:
<<: *env
restart: always
volumes:
- /absolute/path/to/services/ui/widget/:/app/
- /absolute/path/to/.env/:/app/
And this should be your Dockerfile if you use volumesindocker-compose`:
FROM node:14
WORKDIR /app
USER root
# create new user (only root can do this) and assign owenership to newly created user
RUN echo "$(date '+%Y-%m-%d %H:%M:%S'): ======> Setup Appusr" \
&& groupadd -g 1001 appusr \
&& useradd -r -u 1001 -g appusr appusr \
&& mkdir /home/appusr/ \
&& chown -R appusr:appusr /home/appusr/\
&& chown -R appusr:appusr /app
# switch to new created user so that appuser will be responsible for all files and has access
USER appusr:appusr
# installing deps
RUN npm install
You problem is that you are referencing a file which is outside Dockerfile context. By default, is the location from where you execute the build command.
From docker documentation - Copy section:
The path must be inside the context of the build; you cannot COPY ../something /something, because the first step of a docker build is to send the context directory (and subdirectories) to the docker daemon.
However, you can use the parameter -f to specify the dockerfile independently of the folder you are running your build. So you could use the next line executing it from projects:
docker build -f ./deployment/Dockerfile .
You will need to modify your copy lines as well to point at the right location.
COPY ./services/ui/widget/ /app/
COPY ./.env /app/

Docker error can't copy a file after build it

I'm trying to copy my ./dist after building my angular app.
here is my Dockerfile
# Create image based off of the official Node 10 image
FROM node:12-alpine
RUN apk update && apk add --no-cache make git
RUN mkdir -p /home/project/frontend
# Change directory so that our commands run inside this new directory
WORKDIR /home/project/frontend
# Copy dependency definitions
COPY package*.json ./
RUN npm cache verify
## installing packages
RUN npm install
COPY ./ ./
RUN npm run build --output-path=./dist
COPY /dist /var/www/front
but when I run docker-compose build dashboard I get this error
Service 'dashboard' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builderxxx/dist: no such file or directory
I don't know why is there something wrong?
if you need to check also docker-compose file
...
dashboard:
container_name: dashboard
build: ./frontend
image: dashboard
container_name: dashboard
restart: unless-stopped
networks:
- app-network
...
The Dockerfile COPY directive copies content from the build context (the host-system directory in the build: line) into the image. If you're just trying to move around content within the image, you can RUN cp or RUN mv to use the ordinary Linux shell commands instead.
RUN npm run build --output-path=./dist \
&& cp -a dist /var/www/front

Build fails when importing external package with Golang and Docker

I can't build this simple example of confluent kafka using Docker. Probably a trick with go path or an special build parameter, can't find out, tried all the default folders from go, no success.
Dockerfile
FROM golang:alpine AS builder
# Set necessary environmet variables needed for our image
ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64
ADD . /go/app
# Install librdkafka
RUN apk add librdkafka-dev pkgconf
# Move to working directory /build
WORKDIR /go/app
# Copy and download dependency using go mod
COPY go.mod .
RUN go mod download
# Copy the code into the container
COPY . .
# Build the application
RUN go build -o main .
# Run test
RUN go test ./... -v
# Move to /dist directory as the place for resulting binary folder
WORKDIR /dist
# Copy binary from build to main folder
RUN cp /go/app/main .
############################
# STEP 2 build a small image
############################
FROM scratch
COPY --from=builder /dist/main /
# Command to run the executable
ENTRYPOINT ["/main"]
Source
import (
"fmt"
"github.com/confluentinc/confluent-kafka-go/kafka"
"os"
)
func main() {
if len(os.Args) != 3 {
fmt.Fprintf(os.Stderr, "Usage: %s <broker> <topic>\n",
os.Args[0])
os.Exit(1)
}
broker := os.Args[1]
topic := os.Args[2]
p, err := kafka.NewProducer(&kafka.ConfigMap{"bootstrap.servers": broker})
if err != nil {
fmt.Printf("Failed to create producer: %s\n", err)
os.Exit(1)
}
fmt.Printf("Created Producer %v\n", p)
deliveryChan := make(chan kafka.Event)
value := "Hello Go!"
err = p.Produce(&kafka.Message{
TopicPartition: kafka.TopicPartition{Topic: &topic, Partition: kafka.PartitionAny},
Value: []byte(value),
Headers: []kafka.Header{{Key: "myTestHeader", Value: []byte("header values are binary")}},
}, deliveryChan)
e := <-deliveryChan
m := e.(*kafka.Message)
if m.TopicPartition.Error != nil {
fmt.Printf("Delivery failed: %v\n", m.TopicPartition.Error)
} else {
fmt.Printf("Delivered message to topic %s [%d] at offset %v\n",
*m.TopicPartition.Topic, m.TopicPartition.Partition, m.TopicPartition.Offset)
}
close(deliveryChan)
}
Error
./producer_example.go:37:12: undefined: kafka.NewProducer
./producer_example.go:37:31: undefined: kafka.ConfigMap
./producer_example.go:48:28: undefined: kafka.Event
./producer_example.go:51:19: undefined: kafka.Message
Edit
I can confirm that using the musl build tag works:
FROM golang:alpine as build
WORKDIR /go/src/app
# Set necessary environmet variables needed for our image
ENV GOOS=linux GOARCH=amd64
COPY . .
RUN apk update && apk add gcc librdkafka-dev openssl-libs-static zlib-static zstd-libs libsasl librdkafka-static lz4-dev lz4-static zstd-static libc-dev musl-dev
RUN go build -tags musl -ldflags '-w -extldflags "-static"' -o main
FROM scratch
COPY --from=build /go/src/app/main /
# Command to run the executable
ENTRYPOINT ["/main"]
Works with the test setup as shown below.
Ok, the used version 1.4.0 of github.com/confluentinc/confluent-kafka-go/kafka seems to be generally incompatible with at least the current state of alpine 3.11.
Furthermore, despite my best efforts, I was unable to build a statically compiled binary, fit for the use with FROM scratch.
However, I was able to get you code running against a current version of Kafka. The image is a bit bigger, but I guess working and a bit bigger is better than not working and elegant.
Todos
1. Downgrade to confluent-kafka-go#v1.1.0
As simple as
$ go get -u -v github.com/confluentinc/confluent-kafka-go#v1.1.0
2. Modify your Dockerfile
You were lacking some build dependencies to begin with. And obviously, we need a runtime dependency as well, since we do not use FROM scratch any more. Please note that I also tried to simplify it and left jwilder/dockerize in, which I used so that I do not have to time my test setup:
FROM golang:alpine as build
# The default location is /go/src
WORKDIR /go/src/app
ENV GOOS=linux \
GOARCH=amd64
# We simply copy everything to /go/src/app
COPY . .
# Add the required build libraries
RUN apk update && apk add gcc librdkafka-dev zstd-libs libsasl lz4-dev libc-dev musl-dev
# Run the build
RUN go build -o main
FROM alpine
# We use dockerize to make sure the kafka sever is up and running before the command starts.
ENV DOCKERIZE_VERSION v0.6.1
ENV KAFKA kafka
# Add dockerize
RUN apk --no-cache upgrade && apk --no-cache --virtual .get add curl \
&& curl -L -O https://github.com/jwilder/dockerize/releases/download/${DOCKERIZE_VERSION}/dockerize-linux-amd64-${DOCKERIZE_VERSION}.tar.gz \
&& tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz \
&& apk del .get \
# Add the runtime dependency.
&& apk add --no-cache librdkafka
# Fetch the binary
COPY --from=build /go/src/app/main /
# Wait for kafka to come up, only then start /main
ENTRYPOINT ["sh","-c","/usr/local/bin/dockerize -wait tcp://${KAFKA}:9092 /main kafka test"]
3. Test it
I created a docker-compose.yaml to check wether everything works:
version: "3.7"
services:
zookeeper:
image: 'bitnami/zookeeper:3'
ports:
- '2181:2181'
volumes:
- 'zookeeper_data:/bitnami'
environment:
- ALLOW_ANONYMOUS_LOGIN=yes
kafka:
image: 'bitnami/kafka:2'
ports:
- '9092:9092'
volumes:
- 'kafka_data:/bitnami'
environment:
- KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
- ALLOW_PLAINTEXT_LISTENER=yes
depends_on:
- zookeeper
server:
image: fals/kafka-main
build: .
command: "kafka test"
volumes:
zookeeper_data:
kafka_data:
You can check that the setup works with:
$ docker-compose build && docker-compose up -d && docker-compose logs -f server
[...]
server_1 | 2020/04/18 18:37:33 Problem with dial: dial tcp 172.24.0.4:9092: connect: connection refused. Sleeping 1s
server_1 | 2020/04/18 18:37:34 Connected to tcp://kafka:9092
server_1 | Created Producer rdkafka#producer-1
server_1 | Delivered message to topic test [0] at offset 0
server_1 | 2020/04/18 18:37:36 Command finished successfully.
kfka_server_1 exited with code 0

Automate project in laravel

I have an app in Laravel with .env.local file (a and I made the next docker-compose file:
api:
container_name: nadal_api
build:
context: .
dockerfile: Dockerfile
volumes:
- .:/var/www/html/app
ports:
- ${APP_PORT}:80
links:
- db
- redis
And my Dockerfile:
FROM composer:latest AS composer
WORKDIR /var/www/html/app/
FROM php:7.2-fpm-stretch
RUN apt-get update && apt-get install -y \
supervisor \
nginx \
zip
ADD docker/nginx.conf /etc/nginx/nginx.conf ADD
docker/virtualhost.conf /etc/nginx/conf.d/default.conf ADD
docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ARG enviroment
COPY --from=composer /usr/bin/composer /usr/bin/composer
COPY .env.local .env RUN chmod -R g+w /var/www/html/app/bootstrap
RUN composer install RUN php artisan key:generate
EXPOSE 80
CMD ["/usr/bin/supervisord"]
I want to clone the repository and when doing a docker-compose build that does the following in the dockerfile:
rename .env.local to .env
give permissions to the storage folder. I have an error in this line
RUN chmod -R g+w /var/www/html/app/bootstrap
chmod: cannot access '/var/www/html/app/bootstrap': No such file or
directory
docker-compose.yaml: ${APP_PORT} take values from .env.local (I tried with env_file but it does not work
In your Dockerfile there is no COPY action to copy all your current project code into created image. Therefore bootstrap folder is not exist in your image. So chmod tells you exactly that.
Volumes (this line - .:/var/www/html/app) will sync your current directory with container later when it will be created depending on image structure. So if you want to give permissions to bootstrap folder then copy project code into image before giving permissions to it.
Add this line before permission operations to make folders accessible.
COPY . /var/www/html/app

Resources