Compare commits

..

1 Commits

Author SHA1 Message Date
Xe Iaso
bc9c6ffa89 docs(admin/policy): document ReadWritePaths for logging to files
The default Anubis systemd configuration is very restrictive in
order to prevent any possible compromise of Anubis to be useful
by threat actors. As such, it assumes all logs will be pushed to
the system journal. Some administrators do not want Anubis' logs
to be pushed to the system journal and want Anubis to log to a
file instead.

This change documents how to set up ReadWritePaths in the Anubis
systemd configuration such that Anubis can lot to a file as
administrators expect.

Closes: #1468
Signed-off-by: Xe Iaso <me@xeiaso.net>
2026-02-19 12:18:00 +00:00
6 changed files with 31 additions and 111 deletions

View File

@@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
<!-- This changes the project to: -->
- Fix CEL internal errors when iterating `headers`/`query` map wrappers by implementing map iterators for `HTTPHeaders` and `URLValues` ([#1465](https://github.com/TecharoHQ/anubis/pull/1465)).
## v1.25.0: Necron

View File

@@ -393,6 +393,32 @@ logging:
When files are rotated out, the old files will be named after the rotation timestamp in [RFC 3339 format](https://www.rfc-editor.org/rfc/rfc3339).
:::note
If you are running Anubis in systemd via a native package, the default systemd unit settings are very restrictive and will forbid writing to folders in `/var/log`. In order to fix this, please make a [drop-in unit](https://www.flatcar.org/docs/latest/setup/systemd/drop-in-units/) like the following:
```text
# /etc/systemd/anubis@instance-name.service.d/50-var-log-readwrite.conf
[Service]
ReadWritePaths=/run /var/log/anubis
```
Once you write this to the correct place, reload the systemd configuration:
```text
sudo systemctl daemon-reload
```
And then restart Anubis:
```text
sudo systemctl restart anubis@instance-name
```
You may be required to make drop-ins for each Anubis instance depending on the facts and circumstances of your deployment.
:::
### `stdio` sink
By default, Anubis logs everything to the standard error stream of its process. This requires no configuration:

View File

@@ -1,44 +0,0 @@
package policy
import (
"net/http"
"testing"
"github.com/TecharoHQ/anubis/internal/dns"
"github.com/TecharoHQ/anubis/lib/config"
"github.com/TecharoHQ/anubis/lib/store/memory"
)
func newTestDNS(t *testing.T) *dns.Dns {
t.Helper()
ctx := t.Context()
memStore := memory.New(ctx)
cache := dns.NewDNSCache(300, 300, memStore)
return dns.New(ctx, cache)
}
func TestCELChecker_MapIterationWrappers(t *testing.T) {
cfg := &config.ExpressionOrList{
Expression: `headers.exists(k, k == "Accept") && query.exists(k, k == "format")`,
}
checker, err := NewCELChecker(cfg, newTestDNS(t))
if err != nil {
t.Fatalf("creating CEL checker failed: %v", err)
}
req, err := http.NewRequest(http.MethodGet, "https://example.com/?format=json", nil)
if err != nil {
t.Fatalf("making request failed: %v", err)
}
req.Header.Set("Accept", "application/json")
got, err := checker.Check(req)
if err != nil {
t.Fatalf("checking expression failed: %v", err)
}
if !got {
t.Fatal("expected expression to evaluate true")
}
}

View File

@@ -66,9 +66,7 @@ func (h HTTPHeaders) Get(key ref.Val) ref.Val {
return result
}
func (h HTTPHeaders) Iterator() traits.Iterator {
return newMapIterator(h.Header)
}
func (h HTTPHeaders) Iterator() traits.Iterator { panic("TODO(Xe): implement me") }
func (h HTTPHeaders) IsZeroValue() bool {
return len(h.Header) == 0

View File

@@ -1,60 +0,0 @@
package expressions
import (
"errors"
"maps"
"reflect"
"slices"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
)
var ErrNotImplemented = errors.New("expressions: not implemented")
type stringSliceIterator struct {
keys []string
idx int
}
func (s *stringSliceIterator) Value() any {
return s
}
func (s *stringSliceIterator) ConvertToNative(typeDesc reflect.Type) (any, error) {
return nil, ErrNotImplemented
}
func (s *stringSliceIterator) ConvertToType(typeValue ref.Type) ref.Val {
return types.NewErr("can't convert from %q to %q", types.IteratorType, typeValue)
}
func (s *stringSliceIterator) Equal(other ref.Val) ref.Val {
return types.NewErr("can't compare %q to %q", types.IteratorType, other.Type())
}
func (s *stringSliceIterator) Type() ref.Type {
return types.IteratorType
}
func (s *stringSliceIterator) HasNext() ref.Val {
return types.Bool(s.idx < len(s.keys))
}
func (s *stringSliceIterator) Next() ref.Val {
if s.HasNext() != types.True {
return nil
}
val := s.keys[s.idx]
s.idx++
return types.String(val)
}
func newMapIterator(m map[string][]string) traits.Iterator {
return &stringSliceIterator{
keys: slices.Collect(maps.Keys(m)),
idx: 0,
}
}

View File

@@ -1,6 +1,7 @@
package expressions
import (
"errors"
"net/url"
"reflect"
"strings"
@@ -10,6 +11,8 @@ import (
"github.com/google/cel-go/common/types/traits"
)
var ErrNotImplemented = errors.New("expressions: not implemented")
// URLValues is a type wrapper to expose url.Values into CEL programs.
type URLValues struct {
url.Values
@@ -66,9 +69,7 @@ func (u URLValues) Get(key ref.Val) ref.Val {
return result
}
func (u URLValues) Iterator() traits.Iterator {
return newMapIterator(u.Values)
}
func (u URLValues) Iterator() traits.Iterator { panic("TODO(Xe): implement me") }
func (u URLValues) IsZeroValue() bool {
return len(u.Values) == 0