Custom UID and GID for subprocesses and files written (#116) Fix #116

- Environment variables `UID` and `GID`, both defaulting to `1000`
- All subprocesses (openvpn, tinyproxy, etc.) run using the UID and GID given
- All files are written with an ownership for the UID and GID given
- Port forwarded file has also ownership for UID, GID and read permission only
This commit is contained in:
Quentin McGaw
2020-03-29 19:52:49 -04:00
committed by GitHub
parent 76cea56864
commit e5adccd9c5
12 changed files with 193 additions and 30 deletions

View File

@@ -36,6 +36,8 @@ ENV VPNSP=pia \
OPENVPN_ROOT=no \ OPENVPN_ROOT=no \
OPENVPN_TARGET_IP= \ OPENVPN_TARGET_IP= \
TZ= \ TZ= \
UID=1000 \
GID=1000 \
# PIA only # PIA only
PASSWORD= \ PASSWORD= \
REGION="Austria" \ REGION="Austria" \
@@ -82,8 +84,8 @@ HEALTHCHECK --interval=3m --timeout=3s --start-period=20s --retries=1 CMD /entry
RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables unbound tinyproxy tzdata && \ RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables unbound tinyproxy tzdata && \
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \ echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
apk add -q --progress --no-cache --update shadowsocks-libev && \ apk add -q --progress --no-cache --update shadowsocks-libev && \
rm -rf /*.zip /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-anchor /usr/sbin/unbound-checkconf /usr/sbin/unbound-control /usr/sbin/unbound-control-setup /usr/sbin/unbound-host /etc/tinyproxy/tinyproxy.conf && \ rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/tinyproxy/tinyproxy.conf && \
adduser nonrootuser -D -H --uid 1000 && \ deluser openvpn && \
chown nonrootuser -R /etc/unbound /etc/tinyproxy && \ deluser tinyproxy && \
chmod 700 /etc/unbound /etc/tinyproxy deluser unbound
COPY --from=builder --chown=1000:1000 /tmp/gobuild/entrypoint /entrypoint COPY --from=builder /tmp/gobuild/entrypoint /entrypoint

View File

@@ -170,6 +170,8 @@ docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io
| `OPENVPN_TARGET_IP` | | (Optional) Specify a target VPN server IP address to use, valid for Mullvad and Private Internet Access | | `OPENVPN_TARGET_IP` | | (Optional) Specify a target VPN server IP address to use, valid for Mullvad and Private Internet Access |
| `OPENVPN_CIPHER` | | Specify a custom cipher to use, use at your own risk. It will also set `ncp-disable` if using AES GCM for PIA | | `OPENVPN_CIPHER` | | Specify a custom cipher to use, use at your own risk. It will also set `ncp-disable` if using AES GCM for PIA |
| `OPENVPN_AUTH` | | Specify a custom auth algorithm to use (i.e. `sha256`) *for pia only* | | `OPENVPN_AUTH` | | Specify a custom auth algorithm to use (i.e. `sha256`) *for pia only* |
| `UID` | `1000` | User ID to run as non root and for ownership of files written |
| `GID` | `1000` | Group ID to run as non root and for ownership of files written |
## Connect to it ## Connect to it

View File

@@ -13,6 +13,7 @@ import (
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
"github.com/qdm12/golibs/network" "github.com/qdm12/golibs/network"
"github.com/qdm12/golibs/signals" "github.com/qdm12/golibs/signals"
"github.com/qdm12/private-internet-access-docker/internal/alpine"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
"github.com/qdm12/private-internet-access-docker/internal/dns" "github.com/qdm12/private-internet-access-docker/internal/dns"
"github.com/qdm12/private-internet-access-docker/internal/env" "github.com/qdm12/private-internet-access-docker/internal/env"
@@ -30,10 +31,6 @@ import (
"github.com/qdm12/private-internet-access-docker/internal/windscribe" "github.com/qdm12/private-internet-access-docker/internal/windscribe"
) )
const (
uid, gid = 1000, 1000
)
func main() { func main() {
logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1) logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1)
if err != nil { if err != nil {
@@ -52,6 +49,7 @@ func main() {
client := network.NewClient(15 * time.Second) client := network.NewClient(15 * time.Second)
// Create configurators // Create configurators
fileManager := files.NewFileManager() fileManager := files.NewFileManager()
alpineConf := alpine.NewConfigurator(logger, fileManager)
ovpnConf := openvpn.NewConfigurator(logger, fileManager) ovpnConf := openvpn.NewConfigurator(logger, fileManager)
dnsConf := dns.NewConfigurator(logger, client, fileManager) dnsConf := dns.NewConfigurator(logger, client, fileManager)
firewallConf := firewall.NewConfigurator(logger, fileManager) firewallConf := firewall.NewConfigurator(logger, fileManager)
@@ -74,6 +72,13 @@ func main() {
e.FatalOnError(err) e.FatalOnError(err)
logger.Info(allSettings.String()) logger.Info(allSettings.String())
err = alpineConf.CreateUser("nonrootuser", allSettings.UID)
e.FatalOnError(err)
err = fileManager.SetOwnership("/etc/unbound", allSettings.UID, allSettings.GID)
e.FatalOnError(err)
err = fileManager.SetOwnership("/etc/tinyproxy", allSettings.UID, allSettings.GID)
e.FatalOnError(err)
if err := ovpnConf.CheckTUN(); err != nil { if err := ovpnConf.CheckTUN(); err != nil {
logger.Warn(err) logger.Warn(err)
err = ovpnConf.CreateTUN() err = ovpnConf.CreateTUN()
@@ -92,7 +97,7 @@ func main() {
openVPNUser = allSettings.Windscribe.User openVPNUser = allSettings.Windscribe.User
openVPNPassword = allSettings.Windscribe.Password openVPNPassword = allSettings.Windscribe.Password
} }
err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, uid, gid) err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, allSettings.UID, allSettings.GID)
e.FatalOnError(err) e.FatalOnError(err)
// Temporarily reset chain policies allowing Kubernetes sidecar to // Temporarily reset chain policies allowing Kubernetes sidecar to
@@ -113,11 +118,11 @@ func main() {
if allSettings.DNS.Enabled { if allSettings.DNS.Enabled {
initialDNSToUse := constants.DNSProviderMapping()[allSettings.DNS.Providers[0]] initialDNSToUse := constants.DNSProviderMapping()[allSettings.DNS.Providers[0]]
dnsConf.UseDNSInternally(initialDNSToUse.IPs[0]) dnsConf.UseDNSInternally(initialDNSToUse.IPs[0])
err = dnsConf.DownloadRootHints(uid, gid) err = dnsConf.DownloadRootHints(allSettings.UID, allSettings.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = dnsConf.DownloadRootKey(uid, gid) err = dnsConf.DownloadRootKey(allSettings.UID, allSettings.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = dnsConf.MakeUnboundConf(allSettings.DNS, uid, gid) err = dnsConf.MakeUnboundConf(allSettings.DNS, allSettings.UID, allSettings.GID)
e.FatalOnError(err) e.FatalOnError(err)
stream, waitFn, err := dnsConf.Start(allSettings.DNS.VerbosityDetailsLevel) stream, waitFn, err := dnsConf.Start(allSettings.DNS.VerbosityDetailsLevel)
e.FatalOnError(err) e.FatalOnError(err)
@@ -135,19 +140,54 @@ func main() {
var connections []models.OpenVPNConnection var connections []models.OpenVPNConnection
switch allSettings.VPNSP { switch allSettings.VPNSP {
case "pia": case "pia":
connections, err = piaConf.GetOpenVPNConnections(allSettings.PIA.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.PIA.Encryption, allSettings.OpenVPN.TargetIP) connections, err = piaConf.GetOpenVPNConnections(
allSettings.PIA.Region,
allSettings.OpenVPN.NetworkProtocol,
allSettings.PIA.Encryption,
allSettings.OpenVPN.TargetIP)
e.FatalOnError(err) e.FatalOnError(err)
err = piaConf.BuildConf(connections, allSettings.PIA.Encryption, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher, allSettings.OpenVPN.Auth) err = piaConf.BuildConf(
connections,
allSettings.PIA.Encryption,
allSettings.OpenVPN.Verbosity,
allSettings.UID,
allSettings.GID,
allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher,
allSettings.OpenVPN.Auth)
e.FatalOnError(err) e.FatalOnError(err)
case "mullvad": case "mullvad":
connections, err = mullvadConf.GetOpenVPNConnections(allSettings.Mullvad.Country, allSettings.Mullvad.City, allSettings.Mullvad.ISP, allSettings.OpenVPN.NetworkProtocol, allSettings.Mullvad.Port, allSettings.OpenVPN.TargetIP) connections, err = mullvadConf.GetOpenVPNConnections(
allSettings.Mullvad.Country,
allSettings.Mullvad.City,
allSettings.Mullvad.ISP,
allSettings.OpenVPN.NetworkProtocol,
allSettings.Mullvad.Port,
allSettings.OpenVPN.TargetIP)
e.FatalOnError(err) e.FatalOnError(err)
err = mullvadConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher) err = mullvadConf.BuildConf(
connections,
allSettings.OpenVPN.Verbosity,
allSettings.UID,
allSettings.GID,
allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher)
e.FatalOnError(err) e.FatalOnError(err)
case "windscribe": case "windscribe":
connections, err = windscribeConf.GetOpenVPNConnections(allSettings.Windscribe.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.Windscribe.Port, allSettings.OpenVPN.TargetIP) connections, err = windscribeConf.GetOpenVPNConnections(
allSettings.Windscribe.Region,
allSettings.OpenVPN.NetworkProtocol,
allSettings.Windscribe.Port,
allSettings.OpenVPN.TargetIP)
e.FatalOnError(err) e.FatalOnError(err)
err = windscribeConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher, allSettings.OpenVPN.Auth) err = windscribeConf.BuildConf(
connections,
allSettings.OpenVPN.Verbosity,
allSettings.UID,
allSettings.GID,
allSettings.OpenVPN.Root,
allSettings.OpenVPN.Cipher,
allSettings.OpenVPN.Auth)
e.FatalOnError(err) e.FatalOnError(err)
} }
@@ -167,7 +207,13 @@ func main() {
e.FatalOnError(err) e.FatalOnError(err)
if allSettings.TinyProxy.Enabled { if allSettings.TinyProxy.Enabled {
err = tinyProxyConf.MakeConf(allSettings.TinyProxy.LogLevel, allSettings.TinyProxy.Port, allSettings.TinyProxy.User, allSettings.TinyProxy.Password, uid, gid) err = tinyProxyConf.MakeConf(
allSettings.TinyProxy.LogLevel,
allSettings.TinyProxy.Port,
allSettings.TinyProxy.User,
allSettings.TinyProxy.Password,
allSettings.UID,
allSettings.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.AllowAnyIncomingOnPort(allSettings.TinyProxy.Port) err = firewallConf.AllowAnyIncomingOnPort(allSettings.TinyProxy.Port)
e.FatalOnError(err) e.FatalOnError(err)
@@ -182,7 +228,11 @@ func main() {
} }
if allSettings.ShadowSocks.Enabled { if allSettings.ShadowSocks.Enabled {
err = shadowsocksConf.MakeConf(allSettings.ShadowSocks.Port, allSettings.ShadowSocks.Password, uid, gid) err = shadowsocksConf.MakeConf(
allSettings.ShadowSocks.Port,
allSettings.ShadowSocks.Password,
allSettings.UID,
allSettings.GID)
e.FatalOnError(err) e.FatalOnError(err)
err = firewallConf.AllowAnyIncomingOnPort(allSettings.ShadowSocks.Port) err = firewallConf.AllowAnyIncomingOnPort(allSettings.ShadowSocks.Port)
e.FatalOnError(err) e.FatalOnError(err)
@@ -202,7 +252,11 @@ func main() {
if err != nil { if err != nil {
logger.Error("port forwarding:", err) logger.Error("port forwarding:", err)
} }
if err := piaConf.WritePortForward(allSettings.PIA.PortForwarding.Filepath, port); err != nil { if err := piaConf.WritePortForward(
allSettings.PIA.PortForwarding.Filepath,
port,
allSettings.UID,
allSettings.GID); err != nil {
logger.Error("port forwarding:", err) logger.Error("port forwarding:", err)
} }
if err := piaConf.AllowPortForwardFirewall(constants.TUN, port); err != nil { if err := piaConf.AllowPortForwardFirewall(constants.TUN, port); err != nil {

6
go.mod
View File

@@ -4,7 +4,7 @@ go 1.13
require ( require (
github.com/kyokomi/emoji v2.1.0+incompatible github.com/kyokomi/emoji v2.1.0+incompatible
github.com/qdm12/golibs v0.0.0-20200224235252-bc16caae82ea github.com/qdm12/golibs v0.0.0-20200329231626-f55b47cd4e96
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.5.1
golang.org/x/sys v0.0.0-20190412213103-97732733099d golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775
) )

8
go.sum
View File

@@ -61,8 +61,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qdm12/golibs v0.0.0-20200224235252-bc16caae82ea h1:ILUt8UU795dKZ2r7p3G44w1/vcGM/FUFXCcePYXYfS8= github.com/qdm12/golibs v0.0.0-20200329231626-f55b47cd4e96 h1:vGvPItljtw8Z0xVJSyE80Z+6zzRZqrHoXr5vx5iB+rI=
github.com/qdm12/golibs v0.0.0-20200224235252-bc16caae82ea/go.mod h1:YULaFjj6VGmhjak6f35sUWwEleHUmngN5IQ3kdvd6XE= github.com/qdm12/golibs v0.0.0-20200329231626-f55b47cd4e96/go.mod h1:YULaFjj6VGmhjak6f35sUWwEleHUmngN5IQ3kdvd6XE=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -70,6 +70,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
@@ -93,6 +95,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=

28
internal/alpine/alpine.go Normal file
View File

@@ -0,0 +1,28 @@
package alpine
import (
"os/user"
"github.com/qdm12/golibs/files"
"github.com/qdm12/golibs/logging"
)
const logPrefix = "alpine configurator"
type Configurator interface {
CreateUser(username string, uid int) error
}
type configurator struct {
fileManager files.FileManager
lookupUID func(uid string) (*user.User, error)
lookupUser func(username string) (*user.User, error)
}
func NewConfigurator(logger logging.Logger, fileManager files.FileManager) Configurator {
return &configurator{
fileManager: fileManager,
lookupUID: user.LookupId,
lookupUser: user.Lookup,
}
}

38
internal/alpine/users.go Normal file
View File

@@ -0,0 +1,38 @@
package alpine
import (
"fmt"
"os/user"
)
// CreateUser creates a user in Alpine with the given UID
func (c *configurator) CreateUser(username string, uid int) error {
UIDStr := fmt.Sprintf("%d", uid)
u, err := c.lookupUID(UIDStr)
_, unknownUID := err.(user.UnknownUserIdError)
if err != nil && !unknownUID {
return fmt.Errorf("cannot create user: %w", err)
} else if u != nil {
if u.Username == username {
return nil
}
return fmt.Errorf("user with ID %d exists with username %q instead of %q", uid, u.Username, username)
}
u, err = c.lookupUser(username)
_, unknownUsername := err.(user.UnknownUserError)
if err != nil && !unknownUsername {
return fmt.Errorf("cannot create user: %w", err)
} else if u != nil {
return fmt.Errorf("cannot create user: user with name %s already exists for ID %s instead of %d", username, u.Uid, uid)
}
passwd, err := c.fileManager.ReadFile("/etc/passwd")
if err != nil {
return fmt.Errorf("cannot create user: %w", err)
}
passwd = append(passwd, []byte(fmt.Sprintf("%s:x:%d:::/dev/null:/sbin/nologin\n", username, uid))...)
if err := c.fileManager.WriteToFile("/etc/passwd", passwd); err != nil {
return fmt.Errorf("cannot create user: %w", err)
}
return nil
}

15
internal/params/ids.go Normal file
View File

@@ -0,0 +1,15 @@
package params
import (
libparams "github.com/qdm12/golibs/params"
)
// GetUID obtains the user ID to use from the environment variable UID
func (p *paramsReader) GetUID() (uid int, err error) {
return p.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000"))
}
// GetGID obtains the group ID to use from the environment variable GID
func (p *paramsReader) GetGID() (gid int, err error) {
return p.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000"))
}

View File

@@ -28,6 +28,10 @@ type ParamsReader interface {
GetDNSOverTLSPrivateAddresses() (privateAddresses []string) GetDNSOverTLSPrivateAddresses() (privateAddresses []string)
GetDNSOverTLSIPv6() (ipv6 bool, err error) GetDNSOverTLSIPv6() (ipv6 bool, err error)
// IDs
GetUID() (uid int, err error)
GetGID() (gid int, err error)
// Firewall getters // Firewall getters
GetExtraSubnets() (extraSubnets []net.IPNet, err error) GetExtraSubnets() (extraSubnets []net.IPNet, err error)

View File

@@ -20,7 +20,7 @@ type Configurator interface {
encryption models.PIAEncryption, targetIP net.IP) (connections []models.OpenVPNConnection, err error) encryption models.PIAEncryption, targetIP net.IP) (connections []models.OpenVPNConnection, err error)
BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool, cipher, auth string) (err error) BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int, root bool, cipher, auth string) (err error)
GetPortForward() (port uint16, err error) GetPortForward() (port uint16, err error)
WritePortForward(filepath models.Filepath, port uint16) (err error) WritePortForward(filepath models.Filepath, port uint16, uid, gid int) (err error)
AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error)
} }

View File

@@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/qdm12/golibs/files"
"github.com/qdm12/private-internet-access-docker/internal/constants" "github.com/qdm12/private-internet-access-docker/internal/constants"
"github.com/qdm12/private-internet-access-docker/internal/models" "github.com/qdm12/private-internet-access-docker/internal/models"
) )
@@ -35,9 +36,13 @@ func (c *configurator) GetPortForward() (port uint16, err error) {
return body.Port, nil return body.Port, nil
} }
func (c *configurator) WritePortForward(filepath models.Filepath, port uint16) (err error) { func (c *configurator) WritePortForward(filepath models.Filepath, port uint16, uid, gid int) (err error) {
c.logger.Info("%s: Writing forwarded port to %s", logPrefix, filepath) c.logger.Info("%s: Writing forwarded port to %s", logPrefix, filepath)
return c.fileManager.WriteLinesToFile(string(filepath), []string{fmt.Sprintf("%d", port)}) return c.fileManager.WriteLinesToFile(
string(filepath),
[]string{fmt.Sprintf("%d", port)},
files.Ownership(uid, gid),
files.Permissions(400))
} }
func (c *configurator) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) { func (c *configurator) AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error) {

View File

@@ -18,6 +18,8 @@ type Settings struct {
Firewall Firewall Firewall Firewall
TinyProxy TinyProxy TinyProxy TinyProxy
ShadowSocks ShadowSocks ShadowSocks ShadowSocks
UID int
GID int
} }
func (s *Settings) String() string { func (s *Settings) String() string {
@@ -32,6 +34,7 @@ func (s *Settings) String() string {
} }
return strings.Join([]string{ return strings.Join([]string{
"Settings summary below:", "Settings summary below:",
fmt.Sprintf("|-- Using UID %d and GID %d", s.UID, s.GID),
s.OpenVPN.String(), s.OpenVPN.String(),
vpnServiceProvider, vpnServiceProvider,
s.DNS.String(), s.DNS.String(),
@@ -115,5 +118,13 @@ func GetAllSettings(params params.ParamsReader) (settings Settings, err error) {
if err != nil { if err != nil {
return settings, err return settings, err
} }
settings.UID, err = params.GetUID()
if err != nil {
return settings, err
}
settings.GID, err = params.GetGID()
if err != nil {
return settings, err
}
return settings, nil return settings, nil
} }