mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-04-19 19:28:22 +00:00
`unix://$PATH` as listen argument will bind aptly to a unix domain socket rather than TCP. This allows binding the API to a UDS rather than a port. Since aptly has no concept of authentication or any amount of high level API hardening one needs to bottle it up in some other manner. Binding to a localhost port is often a step in the right direction, ultimately is still a scary insecure setup as any user on that host getting compromised would mean that the entire archive is compromised as well. UDS on the other hand are basically files and have their access managed by regular file permission. As such, binding to a socket is in fact the least insecure way to listen as you'd have to explicitly open up the socket permissions to an access qualified group. In the most conservative scenario that means no one but the aptly user can talk to the API, in a more practical setup apache might get access as well and proxy the UDS with authentication or limited to GET operations. Using UDS allows reducing the attack surface of the API server while preserving all the flexibility.
89 lines
2.1 KiB
Go
89 lines
2.1 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
|
|
"github.com/smira/aptly/api"
|
|
"github.com/smira/aptly/utils"
|
|
"github.com/smira/commander"
|
|
"github.com/smira/flag"
|
|
)
|
|
|
|
func aptlyAPIServe(cmd *commander.Command, args []string) error {
|
|
var (
|
|
err error
|
|
)
|
|
|
|
if len(args) != 0 {
|
|
cmd.Usage()
|
|
return commander.ErrCommandError
|
|
}
|
|
|
|
// There are only two working options for aptly's rootDir:
|
|
// 1. rootDir does not exist, then we'll create it
|
|
// 2. rootDir exists and is writable
|
|
// anything else must fail.
|
|
// E.g.: Running the service under a different user may lead to a rootDir
|
|
// that exists but is not usable due to access permissions.
|
|
err = utils.DirIsAccessible(context.Config().RootDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
listen := context.Flags().Lookup("listen").Value.String()
|
|
|
|
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)
|
|
|
|
listenURL, err := url.Parse(listen)
|
|
if err == nil && listenURL.Scheme == "unix" {
|
|
file := listenURL.Path
|
|
os.Remove(file)
|
|
listener, err := net.Listen("unix", file)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to listen on: %s\n%s", file, err)
|
|
}
|
|
defer listener.Close()
|
|
err = http.Serve(listener, api.Router(context))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to serve: %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
err = http.ListenAndServe(listen, api.Router(context))
|
|
if err != nil {
|
|
return fmt.Errorf("unable to serve: %s", err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func makeCmdAPIServe() *commander.Command {
|
|
cmd := &commander.Command{
|
|
Run: aptlyAPIServe,
|
|
UsageLine: "serve",
|
|
Short: "start API HTTP service",
|
|
Long: `
|
|
Start HTTP server with aptly REST API. The server can listen to either a port
|
|
or Unix domain socket. When using a socket, Aptly will fully manage the socket
|
|
file.
|
|
|
|
Example:
|
|
|
|
$ aptly api serve -listen=:8080
|
|
$ aptly api serve -listen=unix:///tmp/aptly.sock
|
|
`,
|
|
Flag: *flag.NewFlagSet("aptly-serve", flag.ExitOnError),
|
|
}
|
|
|
|
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening or unix://path to listen on a Unix domain socket")
|
|
cmd.Flag.Bool("no-lock", false, "don't lock the database")
|
|
|
|
return cmd
|
|
|
|
}
|