restrict

package module
v0.0.0-...-09f9331 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 22, 2024 License: BSD-3-Clause Imports: 22 Imported by: 5

Documentation

Overview

Package restrict is a library to secure your application. Targeting mainly OpenBSD and Linux (amd64) with musl-libc. On other operating systems the functions are no-ops to provide seamless compatibility besides Trust() and the Resolver() variants.

  • Jail ability: Using Trust() and Resolver() enables your application to be independent from the systems typical rootCA bundle and allows the usage from system independent dns servers.
  • Syscall allow-listing: Using Syscalls() gives you the ability to use the comfort of OpenBSD's pledge or seccomp on Linux in a pledge like variation.
  • Restricting the filesystem view: Using Access()/AccessLock() lets you fine tune the accessibility of your filesystem with OpenBSD's unveil or Landlock on Linux in a unveil like mode.

We are only supporting the Landlock ABI version (3, 4 is not implmented yet) and seccomp API version (6+). Kernels before version 6.x (formerly 5.13) and without Landlock¹ as LSM and seccomp² are not supported and will print warnings via DefaultLogger or result in an immediate abort on errors (code 255).

Linux support is AMD64 only and musl-libc mainly. Happens to work with glibc as well. Glibc or other libc implementations are not tested or used in production by myself.

ARM64 and/or RISCV64 support may come later at some point.

¹ https://www.kernel.org/doc/html/latest/userspace-api/landlock.html
² https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html

Sets aka promises available on linux:

  • stdio
  • rpath
  • wpath
  • cpath
  • dpath
  • tmppath
  • inet
  • mcast (stub)
  • fattr
  • chown
  • flock
  • unix
  • dns
  • getpw
  • sendfd
  • recvfd
  • tape (stub)
  • tty
  • proc
  • exec
  • prot_exec (openbsd only)
  • settime
  • ps
  • vminfo
  • id
  • pf (openbsd only)
  • route (stub)
  • wroute (stub)
  • audio
  • video
  • bpf
  • unveil (alias landlock)
  • error

See https://man.openbsd.org/pledge.2 for more info.

Linux only:

  • capabilities
  • namespaces

Index

Constants

View Source
const (
	// Resolver DNS connection types
	UDP proto = iota
	TCP
	TLS
)

Variables

View Source
var (
	// ResolverPrefer indicates an IP type to resolve to, if a dns name is passed to Resolver().
	ResolverPrefer IP = IPv6
	// With DNS over TLS acitvated your DNS server needs a certificate that is valid in the CA pool for the destination IP address.
	ResolverTLSVerify bool = true
	// ResolverDialer enables you to set your Timeouts/Deadlines as wanted.
	ResolverDialer *net.Dialer = &net.Dialer{Timeout: time.Second * 2}
)
View Source
var (

	// Logger defaults to Stderr and adds a prefix of "restrict: "
	DefaultLogger = log.New(os.Stderr, "restrict: ", 0)
)

Functions

func Access

func Access(path string, flags string) error

Access tries to behave similar to OpenBSD's unveil syscall.

It limits the filesystem view for that application by defining a path (directory or file) and flags (crwx) as appropiate but independent of the fs permissions. You can call Access() as often as needed, until you call AccessLock() once. A path has to exist prior to the Access() call. If that path is a directory it will enable all filesystem access underneath that path using the given flags.

Beware! The underlaying Landlock works unfortunately unlike the unveil implementation. Know that the first call to Access() does NOT remove visibility of the entire filesystem. You have to call AccessLock() to see that effect. Until then you'll allow full (openat) access by applying unveil/landlock sets to Syscalls(). After AccessLock() you can't take access away by reducing sets/promises like on OpenBSD.

Unlike on unveil on OpenBSD, the landlock implementation on linux passes the restrictions to forked/cloned or execve'd child processes. See SyscallsExec() on linux for more information.

func AccessCerts

func AccessCerts() error

AccessCerts is a convenience function. It allows the typical paths to your operating systems CA and certificate locations to be read.

It represents an alias to Access("/etc/ssl/cert.pem", "r") on OpenBSD to allow reads. See below for files used on Linux/others. You must use AccessLock() to actually lock the filesystem view on Linux. See Access() for details on Linux documentation.

OpenBSD: "/etc/ssl/cert.pem"
Linux: "/etc/ssl/certs", "/etc/ca-certificates", "/etc/ssl/cert.pem", "/etc/pki"
Others: no-op

func AccessLock

func AccessLock() error

AccessLock removes the ability to allow Access() to filesystem objects. You must call it once. If you call it without calling Access() before, then you will essentially disallow the whole filesystem. (Besides the implicit Access() calls through the other given sets if applicable.)

func Debug

func Debug()

Debug toggles debug messages to Logger.

func Disable

func Disable() error

Disable gives you the ability to let all restrict function calls be nil returned, except the Trust function that returns an empty *tls.Config.

Beware! It has to be called before the first restrict function call of Syscalls/Access/Trust/Resolver in the application and all protections are off. A notice will be printed to Logger:

"restrict: All subsequent restrict calls are disabled on your demand!"

func Expert

func Expert()

Expert enables a mode to use restrict outside of main().

Beware! Do not use this unless you really know what you are doing.

func Resolver

func Resolver(dns string) error

Resolver takes an IP address or name of a DNS server and sets it as the DefaultResolver.

Calls are processed via UDP on port 53 with the given IP version (see ResolverPrefer). It is an alias for ResolverX(dns, "53", false, true).

A more advanced approach for usage with non-standard ports or TLS connections that can be accomplished via ResolverX.

This mainly targets standard library functions.

func ResolverTCP

func ResolverTCP(dns string) error

ResolverTCP takes an IP address of a DNS server and sets it as the DefaultResolver. Calls are processed via TCP on port 53 with the given IP version (see ResolverPrefer). It is an alias for ResolverX(dns, "53", false, false).

func ResolverTLS

func ResolverTLS(dns string) error

ResolverTCP takes an IP address of a DNS server and sets it as the DefaultResolver. Calls are processed via TCP on port 853 with the given IP version (see ResolverPrefer). You can control the TLS verification via ResolverTLSVerify global variable. It is an alias for ResolverX(dns, "853", true, false).

func ResolverX

func ResolverX(dns, port string, dot, udp bool) error

ResolverX takes a dns server (ip/hostname), a target port and a boolean to activate DNS over TLS to use TCP and your systems root CA (rpath / AccessCerts()) or given Trust() configuration and lastly a udp boolean indicator that is incompatible with the previous dot boolean. DOT wins if both are set to true.

Using a hostname instead of an IP address triggers a workaround to determine an adequate IP for that host in the prefered (see ResolverPrefer global variable that defaults to IPv6) IP version via the systems nameservers (UDP/53) for that single lookup.

TLS verification is only available for IP addresses, not for hostnames. If your DNS server's IP is not listed in the certficates X509v3 Subject Alternative Name, then you need to disable ResolverTLSVerify and verify your trust otherwise to establish a connection. You can skip verify via global variable ResolverTLSVerify to set as false.

Most public dns providers are equipped like dns.quad9.net, dns.sb, dns0.eu (only IPv4), one.one.one.one, dns.google, dns.opendns.com.

func State

func State()

State prints the actual state of all available restrictions to DefaultLogger().

restrict: Kernel: 7.4
restrict: Expert: false
restrict: Access: true
restrict: · Implicit: false
restrict: · Lock: true
restrict: Syscalls: true
restrict: Resolver: true
restrict: · Target: dns.sb:853 [2a09::] (TLS)
restrict: Trust: false
restrict: · Local: false
restrict: Sets: [stdio rpath dns inet]
restrict: Paths:
restrict: → /home (r)

func Syscalls

func Syscalls(allow string) error

Syscalls tries to behave similar to OpenBSD's pledge syscall.

It forces that application in a syscall restricted operating mode by defining sets (a collection of syscalls, see promises on OpenBSD).

You can call Syscalls() as often as needed, but you can only reduce the allowed sets from the previous call.

The use of an unallowed syscall results in the default action to kill the process and notify about the incident in your kernel syslog. You can avoid this by applying the error set which will return ENOSYS to the calling function.

SyscallsExec is a no-op on linux since Syscalls and Access are inheriting the restriction to it's childs.

func SyscallsExec deprecated

func SyscallsExec(allow string) error

SyscallsExec is a no-op on linux.

Deprecated: Landlock¹ and seccomp² calls are inherited on Syscalls() with linux.

¹ https://www.kernel.org/doc/html/latest/userspace-api/landlock.html#inheritance
² https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html#usage

func Trust

func Trust(pool *x509.CertPool) *tls.Config

Trust sets the RootCA to your given pool and sets default http transport TLS config and returns a pointer to that tls.Config object for you to use it.

Beware! A previous Disable() call will return a barely initialized TLS config object. A call from outside main() without Expert() mode enabled, will print an error message to the DefaultLogger but still return a valid pointer to that tls.Config object.

Types

type IP

type IP uint8

Internet Protocol

const (
	None IP = iota
	IPv4
	IPv6
)

Possible IP versions to set.

Directories

Path Synopsis
examples
dns
dot
tmp

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL