mirror of
https://github.com/hanzozt/zt.git
synced 2026-11-02 11:38:22 +00:00
759 lines
21 KiB
Go
759 lines
21 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 edge
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/Jeffail/gabs"
|
|
"github.com/openziti/edge-api/rest_management_api_client/posture_checks"
|
|
"github.com/openziti/edge-api/rest_model"
|
|
"github.com/openziti/ziti/ziti/cmd/api"
|
|
cmdhelper "github.com/openziti/ziti/ziti/cmd/helpers"
|
|
"github.com/openziti/ziti/ziti/util"
|
|
"github.com/spf13/cobra"
|
|
"io"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// newCreatePostureCheckCmd creates the 'edge controller create posture-check' command
|
|
func newCreatePostureCheckCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "posture-check",
|
|
}
|
|
|
|
cmd.AddCommand(newCreatePostureCheckMacCmd(out, errOut))
|
|
cmd.AddCommand(newCreatePostureCheckDomainCmd(out, errOut))
|
|
cmd.AddCommand(newCreatePostureCheckProcessCmd(out, errOut))
|
|
cmd.AddCommand(newCreatePostureCheckOsCmd(out, errOut))
|
|
cmd.AddCommand(newCreatePostureCheckMfaCmd(out, errOut))
|
|
cmd.AddCommand(newCreatePostureCheckProcessMultiCmd(out, errOut))
|
|
|
|
return cmd
|
|
}
|
|
|
|
type createPostureCheckOptions struct {
|
|
api.EntityOptions
|
|
roleAttributes []string
|
|
}
|
|
|
|
type createPostureCheckMfaOptions struct {
|
|
createPostureCheckOptions
|
|
timeoutSeconds int
|
|
promptOnWake bool
|
|
promptOnUnlock bool
|
|
ignoreLegacyEndpoints bool
|
|
}
|
|
|
|
type createPostureCheckMacOptions struct {
|
|
createPostureCheckOptions
|
|
addresses []string
|
|
}
|
|
|
|
type createPostureCheckDomainOptions struct {
|
|
createPostureCheckOptions
|
|
domains []string
|
|
}
|
|
|
|
type createPostureCheckOsOptions struct {
|
|
createPostureCheckOptions
|
|
os []string
|
|
}
|
|
|
|
type createPostureCheckProcessOptions struct {
|
|
createPostureCheckOptions
|
|
hashes []string
|
|
signer string
|
|
normalizedOs string
|
|
path string
|
|
}
|
|
|
|
type createPostureCheckProcessMultiOptions struct {
|
|
createPostureCheckOptions
|
|
rawBinaryFileHashes []string //csv per process then by pipe delimited, flags parses the CSV
|
|
binaryFileHashes [][]string
|
|
|
|
rawBinarySigners []string //csv per process then by pipe delimited, flags parses the CSV
|
|
binarySigners [][]string
|
|
|
|
semantic string
|
|
osTypes []string
|
|
paths []string
|
|
name string
|
|
}
|
|
|
|
func (options *createPostureCheckOptions) addPostureFlags(cmd *cobra.Command) {
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
cmd.Flags().StringSliceVarP(&options.roleAttributes, "role-attributes", "a", nil, "comma-separated role attributes for the new service")
|
|
}
|
|
|
|
func newCreatePostureCheckMacCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
options := &createPostureCheckMacOptions{
|
|
createPostureCheckOptions: createPostureCheckOptions{
|
|
EntityOptions: api.NewEntityOptions(out, errOut),
|
|
},
|
|
addresses: nil,
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "mac <name>",
|
|
Short: "creates a posture check for MAC addresses",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
options.Cmd = cmd
|
|
options.Args = args
|
|
|
|
err := runCreatePostureCheckMac(options)
|
|
cmdhelper.CheckErr(err)
|
|
},
|
|
SuggestFor: []string{},
|
|
}
|
|
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
options.AddCommonFlags(cmd)
|
|
options.createPostureCheckOptions.addPostureFlags(cmd)
|
|
|
|
cmd.Flags().StringSliceVarP(&options.addresses, "mac-addresses", "m", nil,
|
|
"Set MAC addresses of the posture check")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func newCreatePostureCheckDomainCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
options := &createPostureCheckDomainOptions{
|
|
createPostureCheckOptions: createPostureCheckOptions{
|
|
EntityOptions: api.NewEntityOptions(out, errOut),
|
|
},
|
|
domains: nil,
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "domain <name>",
|
|
Short: "creates a posture check for Windows domains",
|
|
Args: cobra.ExactArgs(1),
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
options.Cmd = cmd
|
|
options.Args = args
|
|
|
|
err := runCreatePostureCheckDomain(options)
|
|
cmdhelper.CheckErr(err)
|
|
},
|
|
SuggestFor: []string{},
|
|
}
|
|
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
options.AddCommonFlags(cmd)
|
|
options.createPostureCheckOptions.addPostureFlags(cmd)
|
|
|
|
cmd.Flags().StringSliceVarP(&options.domains, "domains", "d", nil,
|
|
"Set the domains of the posture check, may be CSV or multiple flags")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func newCreatePostureCheckProcessCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
options := &createPostureCheckProcessOptions{
|
|
createPostureCheckOptions: createPostureCheckOptions{
|
|
EntityOptions: api.NewEntityOptions(out, errOut),
|
|
},
|
|
hashes: nil,
|
|
signer: "",
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: fmt.Sprintf("process <name> <os=%s|%s|%s|%s> <absolutePath>", OsLinux, OsMacOs, OsWindows, OsWindowsServer),
|
|
Short: "creates a posture check for an OS specific process",
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if err := cobra.ExactArgs(3)(cmd, args); err != nil {
|
|
return err
|
|
}
|
|
os := normalizeOsType(args[1])
|
|
if os == "" || os == OsAndroid || os == OsIOS {
|
|
return fmt.Errorf("invalid os type [%s]: expected %s|%s|%s|%s", args[1], OsLinux, OsMacOs, OsWindows, OsWindowsServer)
|
|
}
|
|
|
|
options.normalizedOs = os
|
|
options.path = args[2]
|
|
|
|
return nil
|
|
},
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
options.Cmd = cmd
|
|
options.Args = args
|
|
|
|
err := runCreatePostureCheckProcess(options)
|
|
cmdhelper.CheckErr(err)
|
|
},
|
|
SuggestFor: []string{},
|
|
}
|
|
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
options.AddCommonFlags(cmd)
|
|
options.createPostureCheckOptions.addPostureFlags(cmd)
|
|
|
|
cmd.Flags().StringSliceVarP(&options.hashes, "hash-sigs", "s", nil, "One or more sha512 hashes separated by commas of valid binaries")
|
|
cmd.Flags().StringVarP(&options.signer, "signer-fingerprint", "f", "", "The sha1 hash of a signer certificate")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func newCreatePostureCheckProcessMultiCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
options := &createPostureCheckProcessMultiOptions{
|
|
createPostureCheckOptions: createPostureCheckOptions{
|
|
EntityOptions: api.NewEntityOptions(out, errOut),
|
|
},
|
|
rawBinaryFileHashes: nil,
|
|
rawBinarySigners: nil,
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: fmt.Sprintf("process-multi <name> <semantic=AllOf|AnyOf> <os csv=%s|%s|%s|%s> <absolutePath csv>", OsLinux, OsMacOs, OsWindows, OsWindowsServer),
|
|
Short: "Create a posture check requiring multiple executables and OSs. Provide CSVs of OS names and executable paths.",
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if err := cobra.ExactArgs(4)(cmd, args); err != nil {
|
|
return err
|
|
}
|
|
|
|
options.name = args[0]
|
|
options.semantic = args[1]
|
|
|
|
if options.semantic != string(rest_model.SemanticAllOf) && options.semantic != string(rest_model.SemanticAnyOf) {
|
|
return fmt.Errorf("invalid semantic [%s]: expected %s|%s", options.semantic, rest_model.SemanticAnyOf, rest_model.SemanticAllOf)
|
|
}
|
|
|
|
oses := strings.Split(args[2], ",")
|
|
for _, os := range oses {
|
|
os = normalizeOsType(os)
|
|
if os == "" || os == OsAndroid || os == OsIOS {
|
|
return fmt.Errorf("invalid os type [%s]: expected %s|%s|%s|%s", args[1], OsLinux, OsMacOs, OsWindows, OsWindowsServer)
|
|
}
|
|
|
|
options.osTypes = append(options.osTypes, os)
|
|
}
|
|
|
|
options.paths = strings.Split(args[3], ",")
|
|
|
|
if len(options.paths) != len(options.osTypes) {
|
|
return fmt.Errorf("number of paths supplied does not match number of os types supplied")
|
|
}
|
|
|
|
for _, rawHash := range options.rawBinaryFileHashes {
|
|
hashes := strings.Split(rawHash, "|")
|
|
cleanHashes, err := cleanSha512s(hashes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
options.binaryFileHashes = append(options.binaryFileHashes, cleanHashes)
|
|
}
|
|
|
|
for _, rawSigner := range options.rawBinarySigners {
|
|
signers := strings.Split(rawSigner, "|")
|
|
cleanedSigners, err := cleanSha1s(signers)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
options.binarySigners = append(options.binarySigners, cleanedSigners)
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
options.Cmd = cmd
|
|
options.Args = args
|
|
|
|
err := runCreatePostureCheckProcessMulti(options)
|
|
cmdhelper.CheckErr(err)
|
|
},
|
|
SuggestFor: []string{},
|
|
}
|
|
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
options.AddCommonFlags(cmd)
|
|
options.createPostureCheckOptions.addPostureFlags(cmd)
|
|
|
|
cmd.Flags().StringSliceVarP(&options.rawBinaryFileHashes, "hash-sigs", "s", nil, "One or more sha512 hashes of valid binaries separated by pipe and by comma for processes")
|
|
cmd.Flags().StringSliceVarP(&options.rawBinarySigners, "signer-fingerprints", "f", nil, "One or more sha1 hash of a valid signer certificate separated by pipe and by comma for processes")
|
|
|
|
return cmd
|
|
}
|
|
|
|
const (
|
|
OsAndroid = "Android"
|
|
OsWindows = "Windows"
|
|
OsWindowsServer = "WindowsServer"
|
|
OsMacOs = "macOS"
|
|
OsIOS = "iOS"
|
|
OsLinux = "Linux"
|
|
|
|
PostureCheckTypeDomain = "DOMAIN"
|
|
PostureCheckTypeProcess = "PROCESS"
|
|
PostureCheckTypeMAC = "MAC"
|
|
PostureCheckTypeOS = "OS"
|
|
PostureCheckTypeMFA = "MFA"
|
|
)
|
|
|
|
// Returns the normalized Edge API value or empty string
|
|
func normalizeOsType(os string) string {
|
|
os = strings.ToLower(os)
|
|
switch os {
|
|
case "android":
|
|
return OsAndroid
|
|
case "windows":
|
|
return OsWindows
|
|
case "macos":
|
|
return OsMacOs
|
|
case "ios":
|
|
return OsIOS
|
|
case "linux":
|
|
return OsLinux
|
|
case "windowsserver":
|
|
return OsWindowsServer
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func cleanHexString(in string) string {
|
|
hexClean := regexp.MustCompile("[^a-f0-9]+")
|
|
return hexClean.ReplaceAllString(strings.ToLower(in), "")
|
|
}
|
|
|
|
func cleanSha512s(in []string) ([]string, error) {
|
|
const sha512HexLength = 128
|
|
|
|
hashMap := map[string]struct{}{}
|
|
for _, hash := range in {
|
|
hash = strings.TrimSpace(hash)
|
|
|
|
if len(hash) == 0 {
|
|
continue
|
|
}
|
|
cleanHash := cleanHexString(hash)
|
|
|
|
if len(cleanHash) != sha512HexLength {
|
|
return nil, fmt.Errorf("sha512 hash must be %d hex characters, given [%s], cleaned [%s] with a length of %d", sha512HexLength, hash, cleanHash, len(cleanHash))
|
|
}
|
|
|
|
hashMap[cleanHash] = struct{}{}
|
|
}
|
|
|
|
var hashes []string
|
|
for hash := range hashMap {
|
|
hashes = append(hashes, hash)
|
|
}
|
|
|
|
return hashes, nil
|
|
}
|
|
|
|
func cleanSha1(in string) (string, error) {
|
|
cleanSig := cleanHexString(in)
|
|
|
|
if len(cleanSig) != 40 {
|
|
return "", fmt.Errorf("sha1 hash must be 20 hex characters, given [%s], cleaned [%s] with a length of %d", in, cleanSig, len(cleanSig))
|
|
}
|
|
|
|
return cleanSig, nil
|
|
}
|
|
|
|
func cleanSha1s(in []string) ([]string, error) {
|
|
hashMap := map[string]struct{}{}
|
|
for _, hash := range in {
|
|
hash = strings.TrimSpace(hash)
|
|
|
|
if len(hash) == 0 {
|
|
continue
|
|
}
|
|
cleanHash, err := cleanSha1(hash)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hashMap[cleanHash] = struct{}{}
|
|
}
|
|
|
|
var cleanHashes []string
|
|
for hash := range hashMap {
|
|
cleanHashes = append(cleanHashes, hash)
|
|
}
|
|
|
|
return cleanHashes, nil
|
|
}
|
|
|
|
func runCreatePostureCheckProcess(o *createPostureCheckProcessOptions) error {
|
|
entityData := gabs.New()
|
|
setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeProcess)
|
|
|
|
api.SetJSONValue(entityData, o.normalizedOs, "process", "osType")
|
|
api.SetJSONValue(entityData, o.path, "process", "path")
|
|
|
|
hashes, err := cleanSha512s(o.hashes)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(hashes) > 0 {
|
|
api.SetJSONValue(entityData, hashes, "process", "hashes")
|
|
}
|
|
|
|
if o.signer != "" {
|
|
cleanSigner, err := cleanSha1(o.signer)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
api.SetJSONValue(entityData, cleanSigner, "process", "signerFingerprint")
|
|
}
|
|
|
|
result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options)
|
|
return o.LogCreateResult("posture check", result, err)
|
|
}
|
|
|
|
func runCreatePostureCheckProcessMulti(options *createPostureCheckProcessMultiOptions) error {
|
|
managementClient, err := util.NewEdgeManagementClient(options)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var processes []*rest_model.ProcessMulti
|
|
|
|
for i, osType := range options.osTypes {
|
|
newOsType := rest_model.OsType(osType)
|
|
process := &rest_model.ProcessMulti{
|
|
OsType: &newOsType,
|
|
Path: &options.paths[i],
|
|
}
|
|
|
|
if len(options.binarySigners) > i {
|
|
process.SignerFingerprints = options.binarySigners[i]
|
|
}
|
|
|
|
if len(options.binaryFileHashes) > i {
|
|
process.Hashes = options.binaryFileHashes[i]
|
|
}
|
|
|
|
processes = append(processes, process)
|
|
}
|
|
|
|
semantic := rest_model.Semantic(options.semantic)
|
|
params := posture_checks.NewCreatePostureCheckParams()
|
|
params.PostureCheck = &rest_model.PostureCheckProcessMultiCreate{
|
|
Processes: processes,
|
|
Semantic: &semantic,
|
|
}
|
|
|
|
attributes := rest_model.Attributes(options.roleAttributes)
|
|
|
|
params.PostureCheck.SetRoleAttributes(&attributes)
|
|
params.PostureCheck.SetName(&options.name)
|
|
|
|
resp, err := managementClient.PostureChecks.CreatePostureCheck(params, nil)
|
|
|
|
if err != nil {
|
|
return util.WrapIfApiError(err)
|
|
}
|
|
|
|
checkId := resp.GetPayload().Data.ID
|
|
|
|
if _, err = fmt.Fprintf(options.Out, "%v\n", checkId); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func setPostureCheckEntityValues(entity *gabs.Container, options *createPostureCheckOptions, typeId string) {
|
|
api.SetJSONValue(entity, options.Args[0], "name")
|
|
api.SetJSONValue(entity, options.roleAttributes, "roleAttributes")
|
|
api.SetJSONValue(entity, typeId, "typeId")
|
|
options.SetTags(entity)
|
|
}
|
|
|
|
func cleanMacAddresses(inAddresses []string) ([]string, error) {
|
|
macClean := regexp.MustCompile("[^a-f0-9]+")
|
|
|
|
addressMap := map[string]struct{}{}
|
|
for _, address := range inAddresses {
|
|
cleanAddress := macClean.ReplaceAllString(strings.ToLower(address), "")
|
|
|
|
if len(cleanAddress) < 12 || len(cleanAddress) > 17 {
|
|
return nil, fmt.Errorf("mac address must be 12-17 hex characters, given [%s], cleaned [%s] with a length of %d", address, cleanAddress, len(cleanAddress))
|
|
}
|
|
|
|
addressMap[cleanAddress] = struct{}{}
|
|
}
|
|
|
|
var addresses []string
|
|
for address := range addressMap {
|
|
addresses = append(addresses, address)
|
|
}
|
|
|
|
return addresses, nil
|
|
}
|
|
|
|
// runCreatePostureCheckMac implements the command to create a mac address posture check
|
|
func runCreatePostureCheckMac(o *createPostureCheckMacOptions) (err error) {
|
|
entityData := gabs.New()
|
|
setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeMAC)
|
|
|
|
addresses, err := cleanMacAddresses(o.addresses)
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(addresses) == 0 {
|
|
return fmt.Errorf("must specify at least one MAC Address, multiple values may be separated by commas")
|
|
}
|
|
|
|
api.SetJSONValue(entityData, addresses, "macAddresses")
|
|
|
|
result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
checkId := result.S("data", "id").Data()
|
|
|
|
if _, err = fmt.Fprintf(o.Out, "%v\n", checkId); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func cleanDomains(inDomains []string) []string {
|
|
domainMap := map[string]struct{}{}
|
|
for _, domain := range inDomains {
|
|
cleanDomain := strings.TrimSpace(strings.ToLower(domain))
|
|
|
|
if len(cleanDomain) > 0 {
|
|
domainMap[cleanDomain] = struct{}{}
|
|
}
|
|
}
|
|
|
|
var domains []string
|
|
for domain := range domainMap {
|
|
domains = append(domains, domain)
|
|
}
|
|
|
|
return domains
|
|
}
|
|
|
|
// runCreatePostureCheckDomain implements the command to create a windows domain posture check
|
|
func runCreatePostureCheckDomain(o *createPostureCheckDomainOptions) (err error) {
|
|
entityData := gabs.New()
|
|
setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeDomain)
|
|
|
|
domains := cleanDomains(o.domains)
|
|
|
|
if len(domains) == 0 {
|
|
return fmt.Errorf("must specify at least one domain, multiple values may be separated by commas or multiple flags")
|
|
}
|
|
|
|
api.SetJSONValue(entityData, domains, "domains")
|
|
|
|
result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
checkId := result.S("data", "id").Data()
|
|
|
|
if _, err = fmt.Fprintf(o.Out, "%v\n", checkId); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func newCreatePostureCheckOsCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
options := &createPostureCheckOsOptions{
|
|
createPostureCheckOptions: createPostureCheckOptions{
|
|
EntityOptions: api.NewEntityOptions(out, errOut),
|
|
},
|
|
os: nil,
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "os <name>",
|
|
Short: "creates a posture check for specific operating systems",
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
},
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
options.Cmd = cmd
|
|
options.Args = args
|
|
|
|
err := runCreatePostureCheckOs(options)
|
|
cmdhelper.CheckErr(err)
|
|
},
|
|
SuggestFor: []string{},
|
|
}
|
|
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
options.AddCommonFlags(cmd)
|
|
options.addPostureFlags(cmd)
|
|
cmd.Flags().StringSliceVarP(&options.os, "os", "o", nil,
|
|
"Set OS(es) of the posture check, should be in the format of '<os>:<version>:<version>:...', multiple may be specified via CSV or multiple flags")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func runCreatePostureCheckOs(o *createPostureCheckOsOptions) error {
|
|
var osSpecs []*osSpec
|
|
for i, osStr := range o.os {
|
|
if osSpec, err := parseOsSpec(osStr); err != nil {
|
|
return fmt.Errorf("could not prase os at index [%d]: %v", i, err)
|
|
} else {
|
|
osSpecs = append(osSpecs, osSpec)
|
|
}
|
|
}
|
|
|
|
entityData := gabs.New()
|
|
setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeOS)
|
|
api.SetJSONValue(entityData, osSpecs, "operatingSystems")
|
|
|
|
result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
checkId := result.S("data", "id").Data()
|
|
|
|
if _, err = fmt.Fprintf(o.Out, "%v\n", checkId); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type osSpec struct {
|
|
Type string
|
|
Versions []string
|
|
}
|
|
|
|
func parseOsSpec(osSpecStr string) (*osSpec, error) {
|
|
splits := strings.Split(osSpecStr, ":")
|
|
|
|
osType := normalizeOsType(splits[0])
|
|
|
|
if osType == "" {
|
|
return nil, fmt.Errorf("invalid os type [%s]", splits[0])
|
|
}
|
|
|
|
cleanVersions := []string{}
|
|
//have versions
|
|
if len(splits) > 1 {
|
|
versions := splits[1:]
|
|
|
|
for _, version := range versions {
|
|
cleanVersion := strings.TrimSpace(version)
|
|
cleanVersions = append(cleanVersions, cleanVersion)
|
|
}
|
|
}
|
|
|
|
return &osSpec{
|
|
Type: osType,
|
|
Versions: cleanVersions,
|
|
}, nil
|
|
}
|
|
|
|
func newCreatePostureCheckMfaCmd(out io.Writer, errOut io.Writer) *cobra.Command {
|
|
options := createPostureCheckMfaOptions{
|
|
createPostureCheckOptions: createPostureCheckOptions{
|
|
EntityOptions: api.NewEntityOptions(out, errOut),
|
|
},
|
|
timeoutSeconds: 0,
|
|
promptOnWake: false,
|
|
promptOnUnlock: false,
|
|
ignoreLegacyEndpoints: false,
|
|
}
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "mfa <name>",
|
|
Short: "creates a posture check indicating client-side mfa is required",
|
|
Args: func(cmd *cobra.Command, args []string) error {
|
|
if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
},
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
options.Cmd = cmd
|
|
options.Args = args
|
|
|
|
err := runCreatePostureCheckMfa(&options)
|
|
cmdhelper.CheckErr(err)
|
|
},
|
|
SuggestFor: []string{},
|
|
}
|
|
|
|
// allow interspersing positional args and flags
|
|
cmd.Flags().SetInterspersed(true)
|
|
options.AddCommonFlags(cmd)
|
|
cmd.Flags().IntVarP(&options.timeoutSeconds, "seconds", "s", -1, "Seconds an MFA posture check allows before an additional MFA code must be submitted")
|
|
cmd.Flags().BoolVarP(&options.promptOnWake, "wake", "w", false, "Prompt for MFA code on endpoint wake")
|
|
cmd.Flags().BoolVarP(&options.promptOnUnlock, "unlock", "u", false, "Prompt for MFA code on endpoint unlock")
|
|
cmd.Flags().BoolVar(&options.ignoreLegacyEndpoints, "ignore-legacy", false, "Ignore prompts and timeout for endpoints that do not support MFA timeout/prompts")
|
|
options.addPostureFlags(cmd)
|
|
|
|
return cmd
|
|
}
|
|
func runCreatePostureCheckMfa(o *createPostureCheckMfaOptions) error {
|
|
entityData := gabs.New()
|
|
_, _ = entityData.Set(o.promptOnUnlock, "promptOnUnlock")
|
|
_, _ = entityData.Set(o.promptOnWake, "promptOnWake")
|
|
_, _ = entityData.Set(o.timeoutSeconds, "timeoutSeconds")
|
|
_, _ = entityData.Set(o.ignoreLegacyEndpoints, "ignoreLegacyEndpoints")
|
|
|
|
setPostureCheckEntityValues(entityData, &o.createPostureCheckOptions, PostureCheckTypeMFA)
|
|
|
|
result, err := CreateEntityOfType("posture-checks", entityData.String(), &o.Options)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
checkId := result.S("data", "id").Data()
|
|
|
|
if _, err = fmt.Fprintf(o.Out, "%v\n", checkId); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return nil
|
|
}
|