Policy advisor (#72)

* Add policy advisor CLI. Add ceate/delete config types CLI.

* Update to go 1.14
This commit is contained in:
Paul Lorenz
2020-04-02 13:53:04 -04:00
committed by GitHub
parent d2c48255e9
commit 1610cb9448
10 changed files with 683 additions and 17 deletions
+145
View File
@@ -6,6 +6,7 @@ Ziti 0.13 includes the following:
* New APIs to list existing role attributes used by edge routers, identities and services
* New APIs to list entities related by polices (such as listing edge routers available to a service via service edge router policies)
* Enhancements to the LIST APIs for edge routers, identities and services which allow one to filter by roles
* A policy advisor API, which helps analyze policies and current system state to figure out if an identity should be able to use a service and if not, why not
* CA Auto Enrollment now allows identities to inherit role attributes from the validating CA
* New `identityRole` attributes added to CA entities
* New APIs to list and manage Transit Routers
@@ -15,6 +16,8 @@ Ziti 0.13 includes the following:
* Fabric enhancements
* New Xlink framework encapsulating the router capabilities for creating overlay mesh links.
* Adjustable Xgress MTU size.
* All Ziti Go projects are now being built with Go 1.14
* See here for change to Go in 1.14 - https://golang.org/doc/go1.14
## Making Policies More User Friendly
### Listing Role Attributes in Use
@@ -139,7 +142,149 @@ Example:
id: a949cf80-b11b-4cce-bbb7-d2e4767878a6 name: baz terminator strategy: role attributes: ["development","sales","support"]
id: ad95ec7d-6c05-42b6-b278-2a98a7e502df name: bar terminator strategy: role attributes: ["four","three","two"]
id: e9673c77-7463-4517-a642-641ef35855cf name: foo terminator strategy: role attributes: ["one","three","two"]
## Policy Advisor
This adds a new operation to the /identities endpoint
* Endpoint: /identities
* New operations
* Query related identities: GET /identities/<identity-id>/policy-advice/<service-id>
This will return the following information about the identity and service:
* If the identity can dial the service
* If the identity can bind the service
* How many edge routers the identity has access to
* How many edge routers the service can be accessed through
* Which edge routers the identity and service have in common (if this is none, then the service can't be accessed by the identity)
* Which of the common edge routers are on-line
Example result:
{
"meta": {},
"data": {
"identityId": "700347c8-ca3a-4438-9060-68f7255ee4f8",
"identity": {
"entity": "identities",
"id": "700347c8-ca3a-4438-9060-68f7255ee4f8",
"name": "ssh-host",
"_links": {
"self": {
"href": "./identities/700347c8-ca3a-4438-9060-68f7255ee4f8"
}
}
},
"serviceId": "8fa27a3e-ffb1-4bd1-befa-fcd38a6c26b3",
"service": {
"entity": "services",
"id": "8fa27a3e-ffb1-4bd1-befa-fcd38a6c26b3",
"name": "ssh",
"_links": {
"self": {
"href": "./services/8fa27a3e-ffb1-4bd1-befa-fcd38a6c26b3"
}
}
},
"isBindAllowed": true,
"isDialAllowed": false,
"identityRouterCount": 2,
"serviceRouterCount": 2,
"commonRouters": [
{
"entity": "edge-routers",
"id": "43d220d8-860e-4d80-a25c-97322a7326b4",
"name": "us-west-1",
"_links": {
"self": {
"href": "./edge-routers/43d220d8-860e-4d80-a25c-97322a7326b4"
}
},
"isOnline": false
},
{
"entity": "edge-routers",
"id": "8c118857-c12e-430d-9109-c31f535933f6",
"name": "us-east-1",
"_links": {
"self": {
"href": "./edge-routers/8c118857-c12e-430d-9109-c31f535933f6"
}
},
"isOnline": true
}
]
}
}
The CLI has also been updated with a new policy-advisor common.
Examples:
# Inspect all identities for policy issues
ziti edge controller policy-advisor identities
# Inspect just the jsmith-laptop identity for policy issues with all services that the identity can access
ziti edge controller policy-advisor identities jsmith-laptop
# Inspect the jsmith-laptop identity for issues related to the ssh service
ziti edge controller policy-advisor identities jsmith-laptop ssh
# Inspect all services for policy issues
ziti edge controller policy-advisor services
# Inspect just the ssh service for policy issues for all identities the service can access
ziti edge controller policy-advisor services ssh
# Inspect the ssh service for issues related to the jsmith-laptop identity
ziti edge controller policy-advisor identities ssh jsmith-laptop
Some example output of the CLI:
$ ec policy-advisor identities -q
ERROR: mlapin-laptop (1) -> ssh-backup (0) Common Routers: (0/0) Dial: Y Bind: N
- Service has no edge routers assigned. Adjust service edge router policies.
ERROR: mlapin-laptop (1) -> ssh (2) Common Routers: (0/0) Dial: Y Bind: N
- Identity and services have no edge routers in common. Adjust edge router policies and/or service edge router policies.
ERROR: ndaniels-laptop (1) -> ssh-backup (0) Common Routers: (0/0) Dial: Y Bind: N
- Service has no edge routers assigned. Adjust service edge router policies.
ERROR: ndaniels-laptop (1) -> ssh (2) Common Routers: (0/1) Dial: Y Bind: N
- Common edge routers are all off-line. Bring routers back on-line or adjust edge router policies and/or service edge router policies to increase common router pool.
ERROR: Default Admin
- Identity does not have access to any services. Adjust service policies.
ERROR: jsmith-laptop (2) -> ssh-backup (0) Common Routers: (0/0) Dial: Y Bind: N
- Service has no edge routers assigned. Adjust service edge router policies.
OKAY : jsmith-laptop (2) -> ssh (2) Common Routers: (1/2) Dial: Y Bind: N
ERROR: ssh-host (2) -> ssh-backup (0) Common Routers: (0/0) Dial: N Bind: Y
- Service has no edge routers assigned. Adjust service edge router policies.
OKAY : ssh-host (2) -> ssh (2) Common Routers: (1/2) Dial: N Bind: Y
ERROR: aortega-laptop
- Identity does not have access to any services. Adjust service policies.
ERROR: djones-laptop (0) -> ssh-backup (0) Common Routers: (0/0) Dial: Y Bind: N
- Identity has no edge routers assigned. Adjust edge router policies.
- Service has no edge routers assigned. Adjust service edge router policies.
ERROR: djones-laptop (0) -> ssh (2) Common Routers: (0/0) Dial: Y Bind: N
- Identity has no edge routers assigned. Adjust edge router policies.
$ ec policy-advisor identities aortega-laptop ssh-backup -q
Found identities with id 70567104-d4bd-45f1-8179-bd1e6ab8751f for name aortega-laptop
Found services with id 46e94977-0efc-4e7d-b9ae-cc8df1c95fc1 for name ssh-backup
ERROR: aortega-laptop (0) -> ssh-backup (0) Common Routers: (0/0) Dial: N Bind: N
- No access to service. Adjust service policies.
- Identity has no edge routers assigned. Adjust edge router policies.
- Service has no edge routers assigned. Adjust service edge router policies.
## CA Auto Enrollment Identity Attributes
Identities that are enrolled via a CA can now inherit a static list of identity role attributes. The normal create,
+9 -8
View File
@@ -1,13 +1,14 @@
module github.com/netfoundry/ziti-cmd
go 1.13
go 1.14
//replace github.com/netfoundry/ziti-foundation => ../ziti-foundation
// replace github.com/netfoundry/ziti-foundation => ../ziti-foundation
//replace github.com/netfoundry/ziti-fabric => ../ziti-fabric
// replace github.com/netfoundry/ziti-fabric => ../ziti-fabric
//replace github.com/netfoundry/ziti-sdk-golang => ../ziti-sdk-golang
//replace github.com/netfoundry/ziti-edge => ../ziti-edge
// replace github.com/netfoundry/ziti-sdk-golang => ../ziti-sdk-golang
// replace github.com/netfoundry/ziti-edge => ../ziti-edge
require (
github.com/Jeffail/gabs v1.4.0
@@ -23,10 +24,10 @@ require (
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19
github.com/michaelquigley/pfxlog v0.0.0-20190813191113-2be43bd0dccc
github.com/netfoundry/ziti-edge v0.12.26
github.com/netfoundry/ziti-fabric v0.11.10
github.com/netfoundry/ziti-edge v0.13.0
github.com/netfoundry/ziti-fabric v0.11.11
github.com/netfoundry/ziti-foundation v0.9.6
github.com/netfoundry/ziti-sdk-golang v0.11.12
github.com/netfoundry/ziti-sdk-golang v0.11.14
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.9.1
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0
+6 -8
View File
@@ -224,16 +224,14 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/netfoundry/secretstream v0.1.1 h1:z6T7B5DuOtr9O+SmKaS9DzwOoGLYtgvyTzuPuR5FO7I=
github.com/netfoundry/secretstream v0.1.1/go.mod h1:uasYkYSp0MmNSlKOWJ2sVzxPms8e58TS4ENq4yro86k=
github.com/netfoundry/ziti-edge v0.12.26 h1:z8TsTiEUVZ00LBsJDU7JoOBFsI1OQwVXrad9mtH7YnE=
github.com/netfoundry/ziti-edge v0.12.26/go.mod h1:PmctiYp1M9bP5taqWChTFIhsVnXbZwN6cEY9/xql1qw=
github.com/netfoundry/ziti-fabric v0.11.10 h1:LLzsAAjUSBU3WAa+4RgSR52s34XI1ol+UF5sOIU7LzU=
github.com/netfoundry/ziti-fabric v0.11.10/go.mod h1:Zb4n8ZwksX60BfBATVTY7XtN+8zsALBaVyNn1VBeYCY=
github.com/netfoundry/ziti-foundation v0.9.4 h1:0IsdbPTKJLbGNgq5gWFFwj/FYq+n9pnee69RGfXKli0=
github.com/netfoundry/ziti-foundation v0.9.4/go.mod h1:GN+ALX+7zr1e4vcI2j6VRbaDVcF0wnuih0p9vj22Of0=
github.com/netfoundry/ziti-edge v0.13.0 h1:bSW00f6BdgIjwv1VnrJSEwpX0ROoJIRUy+NfQ7ck1VI=
github.com/netfoundry/ziti-edge v0.13.0/go.mod h1:OvbtCV8qdGUEMesirROfpF8jneuJkXC4Dye5Pw23n64=
github.com/netfoundry/ziti-fabric v0.11.11 h1:G6xaDziZUPO5W1bzxlSp7toJ95CkXpkhA9BIxdnsUcM=
github.com/netfoundry/ziti-fabric v0.11.11/go.mod h1:b4KUJ05JJkK9jmIlXy4TODXIgLHTdoruPe0EJ5HJHPg=
github.com/netfoundry/ziti-foundation v0.9.6 h1:rsZlM05qAa1PERTqcM4YeCilbCd1i95GbGUzh9OdgKU=
github.com/netfoundry/ziti-foundation v0.9.6/go.mod h1:desAxe5jN/V/+cYe99TGEqxtMVdlJ1HfSRzCmuPJD7M=
github.com/netfoundry/ziti-sdk-golang v0.11.12 h1:AopEehvVeW3sl9zCzWnGJThbcL3jTC4Sfu5VA3kWkIY=
github.com/netfoundry/ziti-sdk-golang v0.11.12/go.mod h1:Wjd4fZxjbo2/cVDyq17KxAatqGzAjtXKiyk9XoxDG8s=
github.com/netfoundry/ziti-sdk-golang v0.11.14 h1:C9vRKPW32Kuld/+vpRKEubIQferQNqlhq5FMUL5MLOM=
github.com/netfoundry/ziti-sdk-golang v0.11.14/go.mod h1:YJZ2s/W+o+zUuizRCfKQton+PaNP7l9R+xHVuzcIaAY=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oleiade/reflections v1.0.0 h1:0ir4pc6v8/PJ0yw5AEtMddfXpWBXg9cnG7SgSoJuCgY=
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
@@ -51,6 +51,21 @@ func mapNameToID(entityType string, val string) (string, error) {
return entityId, nil
}
func mapIdToName(entityType string, val string) (string, error) {
list, err := filterEntitiesOfType(entityType, fmt.Sprintf(`id="%s"`, val), false, nil)
if err != nil {
return "", err
}
if len(list) < 1 {
return "", errors.Errorf("no %v found for id %v", entityType, val)
}
entity := list[0]
name, _ := entity.Path("name").Data().(string)
return name, nil
}
func mapNamesToIDs(entityType string, list ...string) ([]string, error) {
var result []string
for _, val := range list {
@@ -41,6 +41,7 @@ func newCreateCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com
cmd.AddCommand(newCreateAuthenticatorCmd(f, out, errOut))
cmd.AddCommand(newCreateCaCmd(f, out, errOut))
cmd.AddCommand(newCreateConfigCmd(f, out, errOut))
cmd.AddCommand(newCreateConfigTypeCmd(f, out, errOut))
cmd.AddCommand(newCreateEdgeRouterCmd(f, out, errOut))
cmd.AddCommand(newCreateEdgeRouterPolicyCmd(f, out, errOut))
cmd.AddCommand(newCreateTerminatorCmd(f, out, errOut))
@@ -0,0 +1,98 @@
/*
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_controller
import (
"encoding/json"
"fmt"
"io"
"github.com/pkg/errors"
"github.com/Jeffail/gabs"
"github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common"
cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory"
cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers"
"github.com/spf13/cobra"
)
type createConfigTypeOptions struct {
commonOptions
}
// newCreateConfigTypeCmd creates the 'edge controller create service-policy' command
func newCreateConfigTypeCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &createConfigTypeOptions{
commonOptions: commonOptions{
CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut},
},
}
cmd := &cobra.Command{
Use: "config-type <name> <JSON schema>",
Short: "creates a config type managed by the Ziti Edge Controller",
Long: "creates a config type managed by the Ziti Edge Controller",
Args: cobra.RangeArgs(1, 2),
Run: func(cmd *cobra.Command, args []string) {
options.Cmd = cmd
options.Args = args
err := runCreateConfigType(options)
cmdhelper.CheckErr(err)
},
SuggestFor: []string{},
}
// allow interspersing positional args and flags
cmd.Flags().SetInterspersed(true)
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
return cmd
}
// runCreateConfigType create a new configType on the Ziti Edge Controller
func runCreateConfigType(o *createConfigTypeOptions) error {
var schemaMap map[string]interface{}
if len(o.Args) == 2 {
schemaMap = map[string]interface{}{}
if err := json.Unmarshal([]byte(o.Args[1]), &schemaMap); err != nil {
fmt.Printf("Attempted to parse: %v\n", o.Args[1])
fmt.Printf("Failing parsing JSON: %+v\n", err)
return errors.Errorf("unable to parse data as json: %v", err)
}
}
entityData := gabs.New()
setJSONValue(entityData, o.Args[0], "name")
if schemaMap != nil {
setJSONValue(entityData, schemaMap, "schema")
}
result, err := createEntityOfType("config-types", entityData.String(), &o.commonOptions)
if err != nil {
panic(err)
}
configTypeId := result.S("data", "id").Data()
if _, err := fmt.Fprintf(o.Out, "%v\n", configTypeId); err != nil {
panic(err)
}
return err
}
@@ -54,6 +54,7 @@ func newDeleteCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Com
cmd.AddCommand(newDeleteAuthenticatorCmd("authenticator", newOptions()))
cmd.AddCommand(newDeleteCmdForEntityType("ca", runDeleteEntityOfType, newOptions()))
cmd.AddCommand(newDeleteCmdForEntityType("config", runDeleteEntityOfType, newOptions()))
cmd.AddCommand(newDeleteCmdForEntityType("config-type", runDeleteEntityOfType, newOptions()))
cmd.AddCommand(newDeleteCmdForEntityType("edge-router", runDeleteEntityOfType, newOptions()))
cmd.AddCommand(newDeleteCmdForEntityType("edge-router-policy", runDeleteEntityOfType, newOptions()))
cmd.AddCommand(newDeleteCmdForEntityType("identity", runDeleteEntityOfType, newOptions()))
+5 -1
View File
@@ -300,7 +300,11 @@ func filterSubEntitiesOfType(entityType, subType, entityId, filter string, o *co
return nil, err
}
return jsonParsed.S("data").Children()
children, err := jsonParsed.S("data").Children()
if err == gabs.ErrNotObjOrArray {
return nil, nil
}
return children, err
}
func runListEdgeRouters(roleFilters []string, roleSemantic string, options *commonOptions) error {
@@ -0,0 +1,402 @@
/*
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_controller
import (
"fmt"
"github.com/Jeffail/gabs"
"github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/common"
cmdutil "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/factory"
cmdhelper "github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/cmd/helpers"
"github.com/netfoundry/ziti-cmd/ziti/cmd/ziti/util"
"github.com/spf13/cobra"
"io"
)
// newPolicyAdvisor creates a command object for the "controller policy-advisor" command
func newPolicyAdivsorCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "policy-advisor",
Short: "runs sanity checks on various policy related entities managed by the Ziti Edge Controller",
Run: func(cmd *cobra.Command, args []string) {
err := cmd.Help()
cmdhelper.CheckErr(err)
},
}
cmd.AddCommand(newPolicyAdvisorIdentitiesCmd(f, out, errOut))
cmd.AddCommand(newPolicyAdvisorServicesCmd(f, out, errOut))
return cmd
}
type policyAdvisorOptions struct {
commonOptions
quiet bool
}
// newPolicyAdvisorIdentitiesCmd creates the 'edge controller policy-advisor identities' command
func newPolicyAdvisorIdentitiesCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &policyAdvisorOptions{
commonOptions: commonOptions{
CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut},
},
}
cmd := &cobra.Command{
Use: "identities <identity name or id>? <service name or id>?",
Short: "checks policies/connectivity between identities and services",
Args: cobra.RangeArgs(0, 2),
Run: func(cmd *cobra.Command, args []string) {
options.Cmd = cmd
options.Args = args
err := runIdentitiesPolicyAdvisor(options)
cmdhelper.CheckErr(err)
},
SuggestFor: []string{},
}
// allow interspersing positional args and flags
cmd.Flags().SetInterspersed(true)
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
cmd.Flags().BoolVarP(&options.quiet, "quiet", "q", false, "Minimize output by hiding header")
return cmd
}
// newPolicyAdvisorServicesCmd creates the 'edge controller policy-advisor services' command
func newPolicyAdvisorServicesCmd(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &policyAdvisorOptions{
commonOptions: commonOptions{
CommonOptions: common.CommonOptions{Factory: f, Out: out, Err: errOut},
},
}
cmd := &cobra.Command{
Use: "services <service name or id>? <identity name or id>?",
Short: "checks policies/connectivity between services and identities ",
Args: cobra.RangeArgs(0, 2),
Run: func(cmd *cobra.Command, args []string) {
options.Cmd = cmd
options.Args = args
err := runServicesPolicyAdvisor(options)
cmdhelper.CheckErr(err)
},
SuggestFor: []string{},
}
// allow interspersing positional args and flags
cmd.Flags().SetInterspersed(true)
cmd.Flags().BoolVarP(&options.OutputJSONResponse, "output-json", "j", false, "Output the full JSON response from the Ziti Edge Controller")
cmd.Flags().BoolVarP(&options.quiet, "quiet", "q", false, "Minimize output by hiding header")
return cmd
}
// runIdentitiesPolicyAdvisor create a new policyAdvisor on the Ziti Edge Controller
func runIdentitiesPolicyAdvisor(o *policyAdvisorOptions) error {
if len(o.Args) > 0 {
identityId, err := mapNameToID("identities", o.Args[0])
if err != nil {
return err
}
if len(o.Args) > 1 {
serviceId, err := mapNameToID("services", o.Args[1])
if err != nil {
return err
}
if err := outputHeader(o); err != nil {
return err
}
return runPolicyAdvisorForIdentityAndService(identityId, serviceId, o)
}
if err := outputHeader(o); err != nil {
return err
}
return runPolicyAdvisorForIdentity(identityId, o)
}
if err := outputHeader(o); err != nil {
return err
}
return runPolicyAdvisorForIdentities(o)
}
// runServicesPolicyAdvisor create a new policyAdvisor on the Ziti Edge Controller
func runServicesPolicyAdvisor(o *policyAdvisorOptions) error {
if len(o.Args) > 0 {
serviceId, err := mapNameToID("services", o.Args[0])
if err != nil {
return err
}
if len(o.Args) > 1 {
identityId, err := mapNameToID("identities", o.Args[1])
if err != nil {
return err
}
if err := outputHeader(o); err != nil {
return err
}
return runPolicyAdvisorForIdentityAndService(identityId, serviceId, o)
}
if err := outputHeader(o); err != nil {
return err
}
return runPolicyAdvisorForService(serviceId, o)
}
if err := outputHeader(o); err != nil {
return err
}
return runPolicyAdvisorForServices(o)
}
func outputHeader(o *policyAdvisorOptions) error {
if o.quiet {
return nil
}
_, err := fmt.Fprintf(o.Out, "\n"+
"Policy General Guidelines\n"+
" In order for an identity to dial or bind a service, the following must be true:\n"+
" - The identity must have access to the service via a service policy of the correct type (dial or bind)\n"+
" - The identity must have acces to at least one on-line edge router via an edge router policy\n"+
" - The service must have access to at least one on-line edge router via a service edge router policy\n"+
" - There must be at least one on-line edge router that both the identity and service have access to.\n"+
"\n"+
"Policy Advisor Output Guide:\n"+
" STATUS = The status of the identity -> service reachability. Will be OKAY or ERROR. \n"+
" ID = identity name\n"+
" ID ROUTERS = number of routers accessible to the identity via edge router policies.\n"+
" - See edge router polices for an identity: ziti edge controller list identity edge-router-policies <identity>\n"+
" SVC = service name\n"+
" SVC ROUTERS = number of routers accessible to the service via service edge router policies.\n"+
" - See service edge router policies for a service with: ziti edge controller list service service-edge-router-policies <service>\n"+
" ONLINE COMMON ROUTERS = number of routers the identity and service have in common which are online.\n"+
" COMMON ROUTERS = number of routers (online or offline) the identity and service have in common.\n"+
" DIAL_OK = indicates if the identity has permission to dial the service.\n"+
" - See service polices for a service : ziti edge controller list service service-policies <service>\n"+
" - See service polices for an identity: ziti edge controller list identity service-policies <identity>\n"+
" BIND_OK = indicates if the identity has permission to bind the service.\n"+
" ERROR_LIST = if the status is ERROR, error details will be listed on the following lines\n"+
"\n"+
"Output format: STATUS: ID (ID ROUTERS) -> SVC (SVC ROUTERS) Common Routers: (ONLINE COMMON ROUTERS/COMMON ROUTERS) Dial: DIAL_OK Bind: BIND_OK. ERROR_LIST\n"+
"-------------------------------------------------------------------------------\n")
return err
}
func runPolicyAdvisorForIdentities(o *policyAdvisorOptions) error {
skip := 0
done := false
for !done {
filter := fmt.Sprintf(`true skip %v limit 2`, skip)
children, err := filterEntitiesOfType("identities", filter, false, o.Out)
if err != nil {
panic(err)
}
for _, child := range children {
identityId, _ := child.S("id").Data().(string)
if err := runPolicyAdvisorForIdentity(identityId, o); err != nil {
panic(err)
}
}
skip += len(children)
if len(children) == 0 {
done = true
}
}
if skip == 0 {
_, err := fmt.Fprintln(o.Out, "No identities found")
return err
}
return nil
}
func runPolicyAdvisorForServices(o *policyAdvisorOptions) error {
skip := 0
done := false
for !done {
filter := fmt.Sprintf(`true skip %v limit 2`, skip)
children, err := filterEntitiesOfType("services", filter, false, o.Out)
if err != nil {
panic(err)
}
for _, child := range children {
serviceId, _ := child.S("id").Data().(string)
if err := runPolicyAdvisorForService(serviceId, o); err != nil {
panic(err)
}
}
skip += len(children)
if len(children) == 0 {
done = true
}
}
if skip == 0 {
_, err := fmt.Fprintln(o.Out, "No services found")
return err
}
return nil
}
func runPolicyAdvisorForIdentity(identityId string, o *policyAdvisorOptions) error {
skip := 0
done := false
for !done {
filter := "true limit 2"
filter = fmt.Sprintf(`true skip %v limit 2`, skip)
children, err := filterSubEntitiesOfType("identities", "services", identityId, filter, &o.commonOptions)
if err != nil {
panic(err)
}
for _, child := range children {
serviceId, _ := child.S("id").Data().(string)
if err := runPolicyAdvisorForIdentityAndService(identityId, serviceId, o); err != nil {
panic(err)
}
}
skip += len(children)
if len(children) == 0 {
done = true
}
}
if skip == 0 {
identityName, err := mapIdToName("identities", identityId)
if err != nil {
return err
}
_, err = fmt.Fprintf(o.Out, "ERROR: %v %v\n\n", identityName, "\n - Identity does not have access to any services. Adjust service policies.")
return err
}
return nil
}
func runPolicyAdvisorForService(serviceId string, o *policyAdvisorOptions) error {
skip := 0
done := false
for !done {
filter := "true limit 2"
filter = fmt.Sprintf(`true skip %v limit 2`, skip)
children, err := filterSubEntitiesOfType("services", "identities", serviceId, filter, &o.commonOptions)
if err != nil {
panic(err)
}
for _, child := range children {
identityId, _ := child.S("id").Data().(string)
if err := runPolicyAdvisorForIdentityAndService(identityId, serviceId, o); err != nil {
panic(err)
}
}
skip += len(children)
if len(children) == 0 {
done = true
}
}
if skip == 0 {
serviceName, err := mapIdToName("services", serviceId)
if err != nil {
return err
}
_, err = fmt.Fprintf(o.Out, "ERROR: %v %v\n\n", serviceName, "\n - Service is not accessible by any identities. Adjust service policies.")
return err
}
return nil
}
func runPolicyAdvisorForIdentityAndService(identityId, serviceId string, o *policyAdvisorOptions) error {
result, err := util.EdgeControllerList("identities/"+identityId+"/policy-advice/"+serviceId, nil, o.OutputJSONResponse, o.Out)
if err != nil || o.OutputJSONResponse {
return err
}
identityName, _ := result.S("data", "identity", "name").Data().(string)
serviceName, _ := result.S("data", "service", "name").Data().(string)
isBindAllowed, _ := result.S("data", "isBindAllowed").Data().(bool)
isDialAllowed, _ := result.S("data", "isDialAllowed").Data().(bool)
identityRouterCount, _ := result.S("data", "identityRouterCount").Data().(float64)
serviceRouterCount, _ := result.S("data", "serviceRouterCount").Data().(float64)
commonRouters, err := result.S("data", "commonRouters").Children()
if err != nil && err != gabs.ErrNotObjOrArray {
return err
}
commonCount := len(commonRouters)
onlineCount := 0
for _, commonRouter := range commonRouters {
isOnline := commonRouter.S("isOnline").Data().(bool)
if isOnline {
onlineCount++
}
}
status := "OKAY "
detail := ""
if !isBindAllowed && !isDialAllowed {
status = "ERROR"
detail += "\n - No access to service. Adjust service policies."
}
if identityRouterCount < 1 {
status = "ERROR"
detail += "\n - Identity has no edge routers assigned. Adjust edge router policies."
}
if serviceRouterCount < 1 {
status = "ERROR"
detail += "\n - Service has no edge routers assigned. Adjust service edge router policies."
}
if identityRouterCount > 0 && serviceRouterCount > 0 {
if commonCount < 1 {
status = "ERROR"
detail += "\n - Identity and services have no edge routers in common. Adjust edge router policies and/or service edge router policies."
} else if onlineCount < 1 {
status = "ERROR"
detail += "\n - Common edge routers are all off-line. Bring routers back on-line or adjust edge router policies and/or service edge router policies to increase common router pool."
}
}
dialStatus := "Y"
if !isDialAllowed {
dialStatus = "N"
}
bindStatus := "Y"
if !isBindAllowed {
bindStatus = "N"
}
_, err = fmt.Fprintf(o.Out, "%v: %v (%v) -> %v (%v) Common Routers: (%v/%v) Dial: %v Bind: %v %v\n\n",
status, identityName, identityRouterCount, serviceName, serviceRouterCount, onlineCount, commonCount, dialStatus, bindStatus, detail)
return err
}
@@ -48,6 +48,7 @@ func newCmdEdgeController(f cmdutil.Factory, out io.Writer, errOut io.Writer) *c
cmd.AddCommand(newListCmd(f, out, errOut))
cmd.AddCommand(newUpdateCmd(f, out, errOut))
cmd.AddCommand(newVersionCmd(f, out, errOut))
cmd.AddCommand(newPolicyAdivsorCmd(f, out, errOut))
return cmd
}