-
Notifications
You must be signed in to change notification settings - Fork 3
Add Docker support with distroless image #73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # Build stage | ||
| FROM golang:1.23-bookworm AS build | ||
|
|
||
| WORKDIR /src | ||
| COPY . . | ||
|
|
||
| RUN go mod download | ||
| RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /gosh . | ||
|
|
||
| # Runtime stage | ||
| FROM gcr.io/distroless/static-debian12:latest | ||
|
|
||
| # gosh needs root at startup to chroot() and setuid()/setgid() | ||
| # It drops privileges itself to the configured user/group | ||
|
|
||
| # Copy the binary | ||
| COPY --from=build /gosh /gosh | ||
|
|
||
| # Create passwd/group files for user.Lookup() to work | ||
| # Using UID/GID 65532 which is the "nonroot" user in distroless | ||
| COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ | ||
|
|
||
| # We need to add passwd and group files for gosh's user.Lookup() | ||
| # distroless has no shell, so we create these in the build stage | ||
| FROM golang:1.23-bookworm AS passwd-builder | ||
| RUN echo 'root:x:0:0:root:/root:/sbin/nologin' > /tmp/passwd && \ | ||
| echo 'gosh:x:65532:65532:gosh:/nonexistent:/sbin/nologin' >> /tmp/passwd | ||
| RUN echo 'root:x:0:' > /tmp/group && \ | ||
| echo 'gosh:x:65532:' >> /tmp/group | ||
|
|
||
| # Final stage | ||
| FROM gcr.io/distroless/static-debian12:latest | ||
|
|
||
| COPY --from=build /gosh /gosh | ||
| COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ | ||
| COPY --from=passwd-builder /tmp/passwd /etc/passwd | ||
| COPY --from=passwd-builder /tmp/group /etc/group | ||
|
|
||
| # Create store directory (will be owned by root initially, gosh chowns it) | ||
| WORKDIR /data | ||
|
|
||
| EXPOSE 8080 | ||
|
|
||
| ENTRYPOINT ["/gosh"] | ||
| CMD ["-config", "/config/gosh.yml"] | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not a huge fan of having duplicated configuration files. Changes to the main Thus, how about copying it into the container, do the necessary changes via |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| --- | ||
| # Container configuration for gosh | ||
| # | ||
| # Mount structure: | ||
| # /config/gosh.yml - this file | ||
| # /config/index.html - custom index template (optional) | ||
| # /config/favicon.ico - favicon (optional) | ||
| # /config/custom.css - custom styles (optional) | ||
| # /data/ - persistent storage | ||
|
|
||
| user: "gosh" | ||
| group: "gosh" | ||
|
|
||
| store: | ||
| path: "/data/store" | ||
|
|
||
| id_generator: | ||
| type: "random" | ||
| length: 8 | ||
|
|
||
| webserver: | ||
| listen: | ||
| protocol: "tcp" | ||
| bound: ":8080" | ||
|
|
||
| protocol: "http" | ||
|
|
||
| url_prefix: "" | ||
|
|
||
| # Custom index.html template | ||
| custom_index: "/config/index.html" | ||
|
|
||
| # Optional: static files served by gosh | ||
| # Uncomment and adjust as needed | ||
| # static_files: | ||
| # "/favicon.ico": | ||
| # path: "/config/favicon.ico" | ||
| # mime: "image/vnd.microsoft.icon" | ||
| # "/custom.css": | ||
| # path: "/config/custom.css" | ||
| # mime: "text/css" | ||
|
|
||
| item_config: | ||
| max_size: "10MiB" | ||
| max_lifetime: "24h" | ||
|
|
||
| mime_drop: | ||
| - "application/vnd.microsoft.portable-executable" | ||
| - "application/x-msdownload" | ||
| mime_map: | ||
| "text/html": "text/plain" | ||
|
|
||
| contact: "admin@example.com" |
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quite same as https://github.com/oxzi/gosh/pull/73/changes#r2738584441. Is there even a change compared to |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <title>gosh! Go Share</title> | ||
|
|
||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
|
|
||
| <style> | ||
| * { | ||
| font-family: monospace; | ||
| } | ||
|
|
||
| body { | ||
| margin: 0 auto; | ||
| padding: 1rem; | ||
| width: 50%; | ||
| } | ||
|
|
||
| h1 { | ||
| padding-top: 3rem; | ||
| } | ||
|
|
||
| h2 { | ||
| padding-top: 2rem; | ||
| } | ||
|
|
||
| h3 { | ||
| padding-top: 1rem; | ||
| } | ||
|
|
||
| pre { | ||
| background-color: #eee; | ||
| padding: 0.5rem; | ||
| } | ||
|
|
||
| form { | ||
| padding: 0.5rem; | ||
| position: relative; | ||
| margin: auto; | ||
| background-color: #eee; | ||
| } | ||
|
|
||
| #grid { | ||
| display: grid; | ||
| grid-gap: 1rem; | ||
| grid-template-columns: 1fr 1fr; | ||
| grid-template-rows: repeat(3, 3rem); | ||
| margin-bottom: 1rem; | ||
| } | ||
|
|
||
| #grid > * { | ||
| margin: auto 0; | ||
| } | ||
|
|
||
| #grid input[type="checkbox"] { | ||
| margin-right: auto; | ||
| } | ||
|
|
||
| button { | ||
| width: 100%; | ||
| } | ||
| </style> | ||
| </head> | ||
|
|
||
| <body> | ||
| <h1># gosh! Go Share</h1> | ||
| <p> | ||
| Upload your files to this server and share them with your friends or, if | ||
| non-existent, shady people from the Internet. | ||
| </p> | ||
| <p> | ||
| Your file will expire after {{.Expires}} or earlier, if explicitly | ||
| specified. Optionally, the file can be deleted directly after the first | ||
| retrieval. For each upload, a deletion URL will also be generated which | ||
| can be used to delete the file before expiration. In addition, the | ||
| maximum file size is {{.Size}}. | ||
| </p> | ||
| <p> | ||
| This is no place to share questionable or illegal data. Please use another | ||
| service or stop it completely. Get some help. | ||
| </p> | ||
| <p> | ||
| The gosh software can be obtained from | ||
| <a href="https://github.com/oxzi/gosh">https://github.com/oxzi/gosh</a> | ||
| </p> | ||
|
|
||
| <h2>## Posting</h2> | ||
|
|
||
| <h3>### curl</h3> | ||
|
|
||
| HTTP POST your file: | ||
|
|
||
| <pre>$ curl -F 'file=@foo.png' {{.Proto}}://{{.Hostname}}{{.Prefix}}/</pre> | ||
|
|
||
| Burn after reading: | ||
|
|
||
| <pre>$ curl -F 'file=@foo.png' -F 'burn=1' {{.Proto}}://{{.Hostname}}{{.Prefix}}/</pre> | ||
|
|
||
| Set a custom expiry date, e.g., one minute: | ||
|
|
||
| <pre>$ curl -F 'file=@foo.png' -F 'time=1m' {{.Proto}}://{{.Hostname}}{{.Prefix}}/</pre> | ||
|
|
||
| Or all together: | ||
|
|
||
| <pre>$ curl -F 'file=@foo.png' -F 'time=1m' -F 'burn=1' {{.Proto}}://{{.Hostname}}{{.Prefix}}/</pre> | ||
|
|
||
| Print only URL as response: | ||
|
|
||
| <pre>$ curl -F 'file=@foo.png' -F {{.Proto}}://{{.Hostname}}{{.Prefix}}/?onlyURL</pre> | ||
|
|
||
| <h3>### form</h3> | ||
|
|
||
| <form | ||
| action="{{.Proto}}://{{.Hostname}}{{.Prefix}}/" | ||
| method="POST" | ||
| enctype="multipart/form-data"> | ||
| <div id="grid"> | ||
| <label for="file">Your file:</label> | ||
| <input type="file" name="file" /> | ||
| <label for="burn">Burn after reading:</label> | ||
| <input type="checkbox" name="burn" value="1" /> | ||
| <label for="time">Optionally, set a custom expiry date:</label> | ||
| <input | ||
| type="text" | ||
| name="time" | ||
| pattern="{{.DurationPattern}}" | ||
| title="A duration string is sequence of decimal numbers, each with a unit suffix. Valid time units in order are 'y', 'mo', 'w', 'd', 'h', 'm', 's'" | ||
| /> | ||
| </div> | ||
| <button>Upload</button> | ||
| </form> | ||
|
|
||
| <h2>## Privacy</h2> | ||
|
|
||
| This software stores the IP address for each upload. This information is | ||
| stored as long as the file is available. A normal download is logged without | ||
| user information. | ||
|
|
||
| <h2>## Abuse</h2> | ||
|
|
||
| If, for whatever reason, you would like to have a file removed prematurely, | ||
| please write an e-mail to | ||
| <a href="mailto:{{.EMail}}"><{{.EMail}}></a>. Please allow me a | ||
| certain amount of time to react and work on your request. | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| services: | ||
| gosh: | ||
| build: | ||
| context: ../.. | ||
| dockerfile: contrib/docker/Dockerfile | ||
| image: gosh:distroless | ||
| ports: | ||
| - "8080:8080" | ||
| volumes: | ||
| # Config directory with gosh.yml and optional static files | ||
| - ./config:/config:ro | ||
| # Persistent data storage | ||
| - gosh-data:/data | ||
| restart: unless-stopped | ||
|
|
||
| volumes: | ||
| gosh-data: |
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this file for? Is it even being referenced? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| --- | ||
| # Container configuration for gosh | ||
| # | ||
| # Mount structure: | ||
| # /config/gosh.yml - this file | ||
| # /config/index.html - custom index template (optional) | ||
| # /config/favicon.ico - favicon (optional) | ||
| # /config/custom.css - custom styles (optional) | ||
| # /data/ - persistent storage | ||
|
|
||
| user: "gosh" | ||
| group: "gosh" | ||
|
|
||
| store: | ||
| path: "/data/store" | ||
|
|
||
| id_generator: | ||
| type: "random" | ||
| length: 8 | ||
|
|
||
| webserver: | ||
| listen: | ||
| protocol: "tcp" | ||
| bound: ":8080" | ||
|
|
||
| protocol: "http" | ||
|
|
||
| url_prefix: "" | ||
|
|
||
| # Optional: custom index.html template | ||
| # Uncomment if you provide /config/index.html | ||
| # custom_index: "/config/index.html" | ||
|
|
||
| # Optional: static files served by gosh | ||
| # Uncomment and adjust as needed | ||
| # static_files: | ||
| # "/favicon.ico": | ||
| # path: "/config/favicon.ico" | ||
| # mime: "image/vnd.microsoft.icon" | ||
| # "/custom.css": | ||
| # path: "/config/custom.css" | ||
| # mime: "text/css" | ||
|
|
||
| item_config: | ||
| max_size: "10MiB" | ||
| max_lifetime: "24h" | ||
|
|
||
| mime_drop: | ||
| - "application/vnd.microsoft.portable-executable" | ||
| - "application/x-msdownload" | ||
| mime_map: | ||
| "text/html": "text/plain" | ||
|
|
||
| contact: "admin@example.com" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ import ( | |
| "log/slog" | ||
| "os" | ||
| "os/signal" | ||
| "runtime" | ||
|
|
||
| "golang.org/x/sys/unix" | ||
| ) | ||
|
|
@@ -37,7 +38,7 @@ func ensureStoreDir(path, username, groupname string) error { | |
| } | ||
|
|
||
| func mainStore(conf Config) { | ||
| slog.Debug("Starting store child", slog.Any("config", conf.Store)) | ||
| slog.Debug("Starting store child", slog.Any("config", conf.Store), slog.String("arch", runtime.GOARCH)) | ||
|
|
||
| var idGenerator func() (string, error) | ||
| switch conf.Store.IdGenerator.Type { | ||
|
|
@@ -70,26 +71,31 @@ func mainStore(conf Config) { | |
| os.Exit(1) | ||
| } | ||
|
|
||
| err = restrict(restrict_linux_seccomp, | ||
| []string{ | ||
| "@system-service", | ||
| "~@chown", | ||
| "~@clock", | ||
| "~@cpu-emulation", | ||
| "~@debug", | ||
| "~@keyring", | ||
| "~@memlock", | ||
| "~@module", | ||
| "~@mount", | ||
| "~@privileged", | ||
| "~@reboot", | ||
| "~@sandbox", | ||
| "~@setuid", | ||
| "~@swap", | ||
| /* @process */ "~execve", "~execveat", "~fork", "~kill", | ||
| /* @network-io */ "~bind", "~connect", "~listen", | ||
| "fstatat", // for aarch64, same as newfstatat | ||
| }) | ||
| seccompFilter := []string{ | ||
| "@system-service", | ||
| "~@chown", | ||
| "~@clock", | ||
| "~@cpu-emulation", | ||
| "~@debug", | ||
| "~@keyring", | ||
| "~@memlock", | ||
| "~@module", | ||
| "~@mount", | ||
| "~@privileged", | ||
| "~@reboot", | ||
| "~@sandbox", | ||
| "~@setuid", | ||
| "~@swap", | ||
| /* @process */ "~execve", "~execveat", "~fork", "~kill", | ||
| /* @network-io */ "~bind", "~connect", "~listen", | ||
| } | ||
| // fstatat syscall name differs per architecture | ||
| if runtime.GOARCH == "arm64" { | ||
| seccompFilter = append(seccompFilter, "fstatat") | ||
|
Comment on lines
+92
to
+94
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Meh. Seems like I don't know my own library. I assumed that syscallset-go ignore unknown system calls, but it only does so when passing a syscall set. I have changed this with the just released - and already bumped here - version 0.1.7. Thus, no further changes in the Go code are required from this PR. Just rebase :) |
||
| } else { | ||
| seccompFilter = append(seccompFilter, "newfstatat") | ||
|
Comment on lines
+95
to
+96
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not required, since https://github.com/oxzi/syscallset-go/blob/v0.1.7/syscalls.go#L1133-L1333 Furthermore, this binary logic assumes that |
||
| } | ||
| err = restrict(restrict_linux_seccomp, seccompFilter) | ||
| if err != nil { | ||
| slog.Error("Failed to apply seccomp-bpf filter", slog.Any("error", err)) | ||
| os.Exit(1) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't use an LLM (w/o Internet access) to pin "latest" versions.
Especially in this case, these versions are dangerously outdated, as Go only supports the two last major versions, being 1.24 and 1.25 at the time of writing. Since Go 1.23's EOL, there were multiple security fixes in 1.24 and 1.25, many of those might also affect 1.23.
Furthermore, Debian stable is trixie now.