mirror of
https://github.com/openziti/ziti.git
synced 2026-09-23 19:06:38 +00:00
6ad6b3264c
Process posture responses now allow an array of digital signer fingerprints to be submitted and checked.
266 lines
6.6 KiB
Go
266 lines
6.6 KiB
Go
/*
|
|
Copyright NetFoundry, Inc.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package model
|
|
|
|
import (
|
|
"github.com/kataras/go-events"
|
|
cmap "github.com/orcaman/concurrent-map"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
EventIdentityPostureDataAltered = "EventIdentityPostureDataAltered"
|
|
)
|
|
|
|
type PostureCache struct {
|
|
identityToPostureData cmap.ConcurrentMap //identityId -> PostureData
|
|
ticker *time.Ticker
|
|
postureDataTimeout time.Duration
|
|
events.EventEmmiter
|
|
}
|
|
|
|
func newPostureCache() *PostureCache {
|
|
pc := &PostureCache{
|
|
identityToPostureData: cmap.New(),
|
|
ticker: time.NewTicker(10 * time.Second),
|
|
EventEmmiter: events.New(),
|
|
postureDataTimeout: 30 * time.Second,
|
|
}
|
|
|
|
pc.start()
|
|
|
|
return pc
|
|
}
|
|
|
|
func (pc *PostureCache) start() {
|
|
go func() {
|
|
for range pc.ticker.C {
|
|
|
|
changedIdentityIds := map[string]struct{}{}
|
|
|
|
for _, identityId := range pc.identityToPostureData.Keys() {
|
|
pc.identityToPostureData.Upsert(identityId, newPostureData(), func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
|
|
var postureData *PostureData
|
|
if exist {
|
|
postureData = valueInMap.(*PostureData)
|
|
} else {
|
|
postureData = newPostureData()
|
|
}
|
|
|
|
if changed := postureData.Timeout(time.Now().Add(-1 * pc.postureDataTimeout)); changed {
|
|
changedIdentityIds[identityId] = struct{}{}
|
|
}
|
|
|
|
return postureData
|
|
})
|
|
}
|
|
for identityId := range changedIdentityIds {
|
|
pc.Emit(EventIdentityPostureDataAltered, identityId)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (pc *PostureCache) Add(identityId string, postureResponses []*PostureResponse) {
|
|
pc.identityToPostureData.Upsert(identityId, newPostureData(), func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
|
|
var postureData *PostureData
|
|
if exist {
|
|
postureData = valueInMap.(*PostureData)
|
|
} else {
|
|
postureData = newValue.(*PostureData)
|
|
}
|
|
|
|
for _, postureResponse := range postureResponses {
|
|
postureResponse.Apply(postureData)
|
|
}
|
|
|
|
return postureData
|
|
})
|
|
pc.Emit(EventIdentityPostureDataAltered, identityId)
|
|
}
|
|
|
|
func (pc *PostureCache) Evaluate(identityId string, postureChecks []*PostureCheck) bool {
|
|
if val, found := pc.identityToPostureData.Get(identityId); found {
|
|
postureData := val.(*PostureData)
|
|
return postureData.Evaluate(postureChecks)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (pc *PostureCache) PostureData(identityId string) *PostureData {
|
|
if val, found := pc.identityToPostureData.Get(identityId); found {
|
|
return val.(*PostureData)
|
|
}
|
|
|
|
return newPostureData()
|
|
}
|
|
|
|
type PostureData struct {
|
|
Mac *PostureResponseMac `json:"mac"`
|
|
Domain *PostureResponseDomain `json:"domain"`
|
|
Os *PostureResponseOs `json:"os"`
|
|
Processes []*PostureResponseProcess `json:"process"`
|
|
}
|
|
|
|
func (pd *PostureData) Timeout(oldest time.Time) bool {
|
|
changed := false
|
|
changed = pd.Mac.Timeout(oldest) || changed
|
|
changed = pd.Domain.Timeout(oldest) || changed
|
|
changed = pd.Os.Timeout(oldest) || changed
|
|
|
|
for _, process := range pd.Processes {
|
|
changed = process.Timeout(oldest) || changed
|
|
}
|
|
|
|
return changed
|
|
}
|
|
|
|
func (pd *PostureData) Evaluate(checks []*PostureCheck) bool {
|
|
for _, check := range checks {
|
|
if result := check.Evaluate(pd); !result {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func newPostureData() *PostureData {
|
|
return &PostureData{
|
|
Mac: &PostureResponseMac{
|
|
PostureResponse: &PostureResponse{},
|
|
Addresses: []string{},
|
|
},
|
|
Domain: &PostureResponseDomain{
|
|
PostureResponse: &PostureResponse{},
|
|
Name: "",
|
|
},
|
|
Os: &PostureResponseOs{
|
|
PostureResponse: &PostureResponse{},
|
|
Type: "",
|
|
Version: "",
|
|
Build: "",
|
|
},
|
|
Processes: []*PostureResponseProcess{},
|
|
}
|
|
}
|
|
|
|
type PostureResponse struct {
|
|
PostureCheckId string `json:"postureCheckId"`
|
|
TypeId string `json:"-"`
|
|
TimedOut bool `json:"timedOut"`
|
|
LastUpdatedAt time.Time `json:"lastUpdatedAt"`
|
|
SubType PostureResponseSubType `json:"-"`
|
|
}
|
|
|
|
func (pr *PostureResponse) Timeout(oldest time.Time) bool {
|
|
if !pr.TimedOut && pr.LastUpdatedAt.Before(oldest) {
|
|
pr.TimedOut = true
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (pr *PostureResponse) Apply(postureData *PostureData) {
|
|
pr.SubType.Apply(postureData)
|
|
}
|
|
|
|
type PostureResponseSubType interface {
|
|
Apply(postureData *PostureData)
|
|
Timeout(oldest time.Time) bool
|
|
}
|
|
|
|
type PostureResponseMac struct {
|
|
*PostureResponse
|
|
Addresses []string `json:"addresses"`
|
|
}
|
|
|
|
func (pr *PostureResponseMac) Apply(postureData *PostureData) {
|
|
var cleanedAddresses []string
|
|
for _, address := range pr.Addresses {
|
|
cleanedAddresses = append(cleanedAddresses, CleanHexString(address))
|
|
}
|
|
|
|
pr.Addresses = cleanedAddresses
|
|
|
|
postureData.Mac = pr
|
|
postureData.Mac.LastUpdatedAt = time.Now()
|
|
}
|
|
|
|
var macClean = regexp.MustCompile("[^a-f0-9]+")
|
|
|
|
func CleanHexString(hexString string) string {
|
|
return macClean.ReplaceAllString(strings.ToLower(hexString), "")
|
|
}
|
|
|
|
type PostureResponseOs struct {
|
|
*PostureResponse
|
|
Type string `json:"type"`
|
|
Version string `json:"version"`
|
|
Build string `json:"build"`
|
|
}
|
|
|
|
func (pr *PostureResponseOs) Apply(postureData *PostureData) {
|
|
postureData.Os = pr
|
|
postureData.Os.LastUpdatedAt = time.Now()
|
|
}
|
|
|
|
type PostureResponseProcess struct {
|
|
*PostureResponse
|
|
IsRunning bool `json:"isRunning"`
|
|
BinaryHash string `json:"binaryHash"`
|
|
SignerFingerprints []string `json:"signerFingerprints"`
|
|
}
|
|
|
|
func (pr *PostureResponseProcess) Apply(postureData *PostureData) {
|
|
found := false
|
|
|
|
for i, fingerprint := range pr.SignerFingerprints {
|
|
pr.SignerFingerprints[i] = CleanHexString(fingerprint)
|
|
}
|
|
|
|
pr.BinaryHash = CleanHexString(pr.BinaryHash)
|
|
|
|
for i, process := range postureData.Processes {
|
|
if process.PostureCheckId == pr.PostureCheckId {
|
|
postureData.Processes[i] = pr
|
|
postureData.Processes[i].LastUpdatedAt = time.Now()
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
pr.LastUpdatedAt = time.Now()
|
|
postureData.Processes = append(postureData.Processes, pr)
|
|
}
|
|
}
|
|
|
|
type PostureResponseDomain struct {
|
|
*PostureResponse
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
func (pr *PostureResponseDomain) Apply(postureData *PostureData) {
|
|
postureData.Domain = pr
|
|
postureData.Domain.LastUpdatedAt = time.Now()
|
|
}
|