Documentation
¶
Overview ¶
Package decryptprofile is the named SSL-decryption-profile engine: a PAN-OS-style "how to decrypt" object that policy rules reference by name to control HOW an inspected (SSLAction=Inspect) tunnel is decrypted — whether to inspect natively as HTTP/2, the upstream server-certificate-verification posture, the unsupported-TLS failure posture, the TLS version floor/cap, and the per-stream inactivity bound. It is the "how" half that complements the "what to match" half already in package main's policy rules + sslbypass.
This engine owns storage + validation ONLY. The resolvers that turn a matched rule's profile reference into a runtime decision (resolveStripALPN and friends) live in package main on the proxy hot path, mirroring how catgroup exposes the pure store while categoryGroupMatchesHost stays in main.
Concurrency: an RWMutex protects the store; reads (GetByName) take RLock, writes rebuild order under Lock. All validation is enforced in Add/Update AND ReplaceAll, because profiles are written by THREE paths — the admin API, config import, and CP→DP snapshot apply — and a handler-only check would be bypassed by the latter two.
Index ¶
- Constants
- func Validate(p *Profile) error
- type Profile
- type Store
- func (s *Store) Add(p Profile) (*Profile, error)
- func (s *Store) Delete(name string) error
- func (s *Store) DeleteByID(id string) (string, error)
- func (s *Store) FailOpenScope(name string) (id string, ok bool)
- func (s *Store) FailOpenScopeByID(id string) (scope string, resolved bool)
- func (s *Store) GetByID(id string) *Profile
- func (s *Store) GetByName(name string) *Profile
- func (s *Store) List() []Profile
- func (s *Store) Load(path string) error
- func (s *Store) Names() []string
- func (s *Store) Path() string
- func (s *Store) Rename(id, newName string) (oldName string, err error)
- func (s *Store) ReplaceAll(profiles []Profile)
- func (s *Store) Save()
- func (s *Store) SetPathForTest(path string)
- func (s *Store) Update(p Profile) error
- func (s *Store) UpdateByID(id string, p Profile) error
Constants ¶
const ( MinStallSecs = 5 MaxStallSecs = 3600 )
Clamp bounds for StallTimeoutSecs. 0 means "engine default" (the caller substitutes sslInspectBodyStallTimeout); any other value must fall in [MinStallSecs, MaxStallSecs]. A too-low value kills legitimate long-poll/SSE/ large-download streams; a too-high value lets a slow-loris stream pin a handler + scan buffer. MaxStallSecs matches the default tunnel-idle ceiling (1h).
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Profile ¶
type Profile struct {
ID string `json:"id"`
Name string `json:"name"`
// InspectHTTP2: nil = inherit (strip → HTTP/1.1, today's default); true =
// native HTTP/2 inspection; false = force strip/HTTP-1.1.
InspectHTTP2 *bool `json:"inspectHttp2,omitempty"`
// CertVerification of the upstream (origin) cert on the inspect leg:
// "" inherit (rule's TLSSkipVerify) | "strict" (verify, block untrusted/expired)
// | "permissive" (verify, allow+log — DEFERRED enforcement) | "skip".
CertVerification string `json:"certVerification,omitempty"`
// OnUnsupported posture when the origin TLS can't be inspected (version/cipher
// below floor): "" inherit | "fail-close" (drop — today's behavior) | "fail-open"
// (raw-relay bypass — DEFERRED, superseded by OnInspectError for fail-open).
OnUnsupported string `json:"onUnsupported,omitempty"`
// OnInspectError is the adaptive decryption-exclusion / fail-open posture when
// an inspected tunnel CANNOT be established because the host is incompatible
// with inspection (origin demands a client cert we can't present, or the TLS
// parameters are unsupported, or a pinned client rejects our forged leaf):
// "" inherit (fail-close, today's behavior) | "fail-close" (502/drop) |
// "fail-open" (record the host in the auto-exclusion cache after a
// confirm-count of distinct clients, rescue the current session where it has
// not yet committed to the client, and bypass subsequent sessions to the host
// until the entry expires). It deliberately does NOT fire on an untrusted/
// expired origin cert — that stays a block. See internal/autoexclude.
OnInspectError string `json:"onInspectError,omitempty"`
// MinTLSVersion / MaxTLSVersion floor and cap on the inspect handshakes:
// "" inherit | "1.2" | "1.3".
MinTLSVersion string `json:"minTlsVersion,omitempty"`
MaxTLSVersion string `json:"maxTlsVersion,omitempty"`
// StallTimeoutSecs per-stream inactivity bound; 0 = engine default, else
// clamped to [MinStallSecs, MaxStallSecs].
StallTimeoutSecs int `json:"stallTimeoutSecs,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
}
Profile is a named decryption profile. Zero/empty fields mean "inherit the default" so an absent or partially-filled profile never silently changes today's behavior (back-compat with the pre-profile inline rule fields).
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store manages persistent decryption profiles with O(1) name lookups.
func (*Store) Add ¶
Add creates a new profile. Validates fields, then name uniqueness. Assigns a short unique ID (a truncated UUID) when absent (ID-preserving otherwise).
func (*Store) DeleteByID ¶ added in v1.0.87
DeleteByID removes the profile with the given stable ID. Returns the removed profile's name (for audit) or an error if not found.
func (*Store) FailOpenScope ¶ added in v1.0.82
FailOpenScope returns the profile's ID and true IFF a profile with the given name exists AND opts into fail-open (OnInspectError=="fail-open"). It is a HOT-PATH accessor (resolveSSLAction calls it per CONNECT for fail-open rules): it reads only two string fields under the RLock and returns NO copy, avoiding the copyOut allocation a full GetByName pays. The learn/cold paths keep the copy-returning accessors.
func (*Store) FailOpenScopeByID ¶ added in v1.0.95
FailOpenScopeByID resolves the autoexclude scope by the profile's stable ULID (references-by-id / rename-safe). resolved=true iff a profile with that id EXISTS; scope is its ID when that profile is fail-open, else "". The ID is AUTHORITATIVE: a resolved fail-close profile returns ("", true) so the caller does NOT fall back to the name — otherwise a rule whose id points at a fail-close profile but whose stale name points at a different fail-open one could get its (fail-close) session bypassed, violating the "fail-close is un-poisonable" invariant. Mirrors resolveDecryptionProfile: name fallback only when the id resolves to no profile at all. No-copy fast path; O(profiles), a small admin set, only on the SSL-inspect CONNECT path.
func (*Store) GetByID ¶ added in v1.0.87
GetByID returns a copy of the profile with the given stable ID, or nil.
func (*Store) GetByName ¶
GetByName returns a profile by name (case-insensitive). O(1). nil if not found.
func (*Store) Load ¶
Load reads profiles from a JSON file. Invalid profiles on disk are skipped with a log line (fail-safe — a corrupt entry never blocks startup or the valid ones).
func (*Store) Rename ¶ added in v1.0.95
Rename changes the display name of the profile with the given stable ID, re-keying the name index (references-by-id: rules link by ID, so the rename is safe — the caller cascades the denormalized name onto referencing rules). Validates the new name is non-empty and not already taken by a DIFFERENT profile. Returns the OLD name (for audit + the caller's cascade). A case-only change updates the display name in place without a collision check.
func (*Store) ReplaceAll ¶
ReplaceAll atomically replaces all profiles (cluster sync / rollback / import). Invalid profiles are skipped (fail-safe) so a bad remote/imported entry never takes down the store or the valid entries. IDs are PRESERVED as provided (backfilled only when empty) so a capture→apply→re-capture round-trip is stable.
func (*Store) Save ¶
func (s *Store) Save()
Save persists the current profiles to disk (atomic write). No-op when path unset.
func (*Store) SetPathForTest ¶
SetPathForTest points persistence at path without loading.
func (*Store) Update ¶
Update replaces an existing profile's fields (by name). Preserves ID + CreatedAt.
func (*Store) UpdateByID ¶ added in v1.0.87
UpdateByID replaces the content of the profile with the given stable ID (rename-safe addressing). Like the name-keyed Update, it edits content and keeps the profile's current name + CreatedAt + ID — position/identity are not changed by an edit. Returns error if no profile carries the id.