kubectl源码分析之auth can-i

 欢迎关注我的公众号:

 目前刚开始写一个月,一共写了18篇原创文章,文章目录如下:

istio多集群探秘,部署了50次多集群后我得出的结论

istio多集群链路追踪,附实操视频

istio防故障利器,你知道几个,istio新手不要读,太难!

istio业务权限控制,原来可以这么玩

istio实现非侵入压缩,微服务之间如何实现压缩

不懂envoyfilter也敢说精通istio系列-http-rbac-不要只会用AuthorizationPolicy配置权限

不懂envoyfilter也敢说精通istio系列-02-http-corsFilter-不要只会vs

不懂envoyfilter也敢说精通istio系列-03-http-csrf filter-再也不用再代码里写csrf逻辑了

不懂envoyfilter也敢说精通istio系列http-jwt_authn-不要只会RequestAuthorization

不懂envoyfilter也敢说精通istio系列-05-fault-filter-故障注入不止是vs

不懂envoyfilter也敢说精通istio系列-06-http-match-配置路由不只是vs

不懂envoyfilter也敢说精通istio系列-07-负载均衡配置不止是dr

不懂envoyfilter也敢说精通istio系列-08-连接池和断路器

不懂envoyfilter也敢说精通istio系列-09-http-route filter

不懂envoyfilter也敢说精通istio系列-network filter-redis proxy

不懂envoyfilter也敢说精通istio系列-network filter-HttpConnectionManager

不懂envoyfilter也敢说精通istio系列-ratelimit-istio ratelimit完全手册

 

————————————————

//创建auth命令
func NewCmdAuth(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{//创建cobra命令
		Use:   "auth",
		Short: "Inspect authorization",
		Long:  `Inspect authorization`,
		Run:   cmdutil.DefaultSubCommandRun(streams.ErrOut),
	}

	cmds.AddCommand(NewCmdCanI(f, streams))//添加can-i子命令
	cmds.AddCommand(NewCmdReconcile(f, streams))//添加reconcile子命令

	return cmds
}
type CanIOptions struct {//can-i结构体
	AllNamespaces   bool
	Quiet           bool
	NoHeaders       bool
	Namespace       string
	AuthClient      authorizationv1client.AuthorizationV1Interface
	DiscoveryClient discovery.DiscoveryInterface

	Verb           string
	Resource       schema.GroupVersionResource
	NonResourceURL string
	Subresource    string
	ResourceName   string
	List           bool

	genericclioptions.IOStreams
}
//创建can-i命令
func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := &CanIOptions{//初始化结构体
		IOStreams: streams,
	}

	cmd := &cobra.Command{//创建cobra命令
		Use:                   "can-i VERB [TYPE | TYPE/NAME | NONRESOURCEURL]",
		DisableFlagsInUseLine: true,
		Short:                 "Check whether an action is allowed",
		Long:                  canILong,
		Example:               canIExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))//准备
			cmdutil.CheckErr(o.Validate())//校验
			var err error
			if o.List {//如果指定--list
				err = o.RunAccessList()//运行list
			} else {
				var allowed bool
				allowed, err = o.RunAccessCheck()//运行check
				if err == nil {
					if !allowed {
						os.Exit(1)
					}
				}
			}
			cmdutil.CheckErr(err)
		},
	}

	cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If true, check the specified action in all namespaces.")//all-namespaces选项
	cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")//quiet选项
	cmd.Flags().StringVar(&o.Subresource, "subresource", o.Subresource, "SubResource such as pod/log or deployment/scale")//subresource选项
	cmd.Flags().BoolVar(&o.List, "list", o.List, "If true, prints all allowed actions.")//list选项
	cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If true, prints allowed actions without headers")//no-headers选项
	return cmd
}
//准备
func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
	if o.List {//如果指定了--list
		if len(args) != 0 {//参数不等于0个报错
			return errors.New("list option must be specified with no arguments")
		}
	} else {
		if o.Quiet {//指定了quiet
			o.Out = ioutil.Discard//设置out
		}

		switch len(args) {//判断参数个数
		case 2://为2个
			o.Verb = args[0]//第0个位动作
			if strings.HasPrefix(args[1], "/") {//第1个参数有/开头
				o.NonResourceURL = args[1]//设置非资源url
				break
			}
			resourceTokens := strings.SplitN(args[1], "/", 2)//用/分割
			restMapper, err := f.ToRESTMapper()//获取restMapper
			if err != nil {
				return err
			}
			o.Resource = o.resourceFor(restMapper, resourceTokens[0])//设置资源
			if len(resourceTokens) > 1 {
				o.ResourceName = resourceTokens[1]//设置资源名称
			}
		default:
			return errors.New("you must specify two or three arguments: verb, resource, and optional resourceName")//报错
		}
	}

	var err error
	client, err := f.KubernetesClientSet()//获取clientset
	if err != nil {
		return err
	}
	o.AuthClient = client.AuthorizationV1()//从clientset获取authClient
	o.DiscoveryClient = client.Discovery()//从clientset获取discoberyClient
	o.Namespace = ""//设置namespace为空
	if !o.AllNamespaces {//没有指定all-namespaces
		o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace
		if err != nil {
			return err
		}
	}

	return nil
}
//校验
func (o *CanIOptions) Validate() error {
	if o.List {//指定了list
		if o.Quiet || o.AllNamespaces || o.Subresource != "" {//list不能和这三个同时指定
			return errors.New("list option can't be specified with neither quiet, all-namespaces nor subresource options")
		}
		return nil
	}

	if o.NonResourceURL != "" {//指定了非资源url
		if o.Subresource != "" {//不能同时指定子资源
			return fmt.Errorf("--subresource can not be used with NonResourceURL")
		}
		if o.Resource != (schema.GroupVersionResource{}) || o.ResourceName != "" {//不能同时指定资源名称
			return fmt.Errorf("NonResourceURL and ResourceName can not specified together")
		}
	} else if !o.Resource.Empty() && !o.AllNamespaces && o.DiscoveryClient != nil {
		if namespaced, err := isNamespaced(o.Resource, o.DiscoveryClient); err == nil && !namespaced {//判断资源是否集群范围
			if len(o.Resource.Group) == 0 {//输出告警
				fmt.Fprintf(o.ErrOut, "Warning: resource '%s' is not namespace scoped\n", o.Resource.Resource)
			} else {
				fmt.Fprintf(o.ErrOut, "Warning: resource '%s' is not namespace scoped in group '%s'\n", o.Resource.Resource, o.Resource.Group)
			}
		}
	}

	if o.NoHeaders {//no-headers必须和list同时指定
		return fmt.Errorf("--no-headers cannot be set without --list specified")
	}
	return nil
}
//执行list
func (o *CanIOptions) RunAccessList() error {
	sar := &authorizationv1.SelfSubjectRulesReview{//创建SelfSubjectRulesReview
		Spec: authorizationv1.SelfSubjectRulesReviewSpec{
			Namespace: o.Namespace,
		},
	}
	response, err := o.AuthClient.SelfSubjectRulesReviews().Create(sar)//应用SelfSubjectRulesReview到服务端
	if err != nil {
		return err
	}

	return o.printStatus(response.Status)//输出结果
}
//执行check
func (o *CanIOptions) RunAccessCheck() (bool, error) {
	var sar *authorizationv1.SelfSubjectAccessReview//定义SelfSubjectAccessReview
	if o.NonResourceURL == "" {//非资源url为空
		sar = &authorizationv1.SelfSubjectAccessReview{//创建SelfSubjectAccessReview
			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
				ResourceAttributes: &authorizationv1.ResourceAttributes{
					Namespace:   o.Namespace,
					Verb:        o.Verb,
					Group:       o.Resource.Group,
					Resource:    o.Resource.Resource,
					Subresource: o.Subresource,
					Name:        o.ResourceName,
				},
			},
		}
	} else {
		sar = &authorizationv1.SelfSubjectAccessReview{//创建SelfSubjectAccessReview
			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
				NonResourceAttributes: &authorizationv1.NonResourceAttributes{
					Verb: o.Verb,
					Path: o.NonResourceURL,
				},
			},
		}
	}

	response, err := o.AuthClient.SelfSubjectAccessReviews().Create(sar)//应用SelfSubjectAccessReview到服务端
	if err != nil {
		return false, err
	}

	if response.Status.Allowed {//结果为allowed打印yes
		fmt.Fprintln(o.Out, "yes")
	} else {
		fmt.Fprint(o.Out, "no")//打印no
		if len(response.Status.Reason) > 0 {//打印reason
			fmt.Fprintf(o.Out, " - %v", response.Status.Reason)
		}
		if len(response.Status.EvaluationError) > 0 {//打印EvaluationError
			fmt.Fprintf(o.Out, " - %v", response.Status.EvaluationError)
		}
		fmt.Fprintln(o.Out)
	}

	return response.Status.Allowed, nil
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hxpjava1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值