2022-05-18 16:14:00 +08:00
/ *
Copyright 2022 The KubeVela Authors .
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
http : //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 cli
import (
"context"
2022-05-18 20:57:39 +08:00
"fmt"
2022-05-18 16:14:00 +08:00
"strings"
"github.com/spf13/cobra"
2022-05-18 20:57:39 +08:00
"golang.org/x/term"
2022-05-18 16:14:00 +08:00
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
2022-05-18 20:57:39 +08:00
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
2022-05-18 16:14:00 +08:00
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/auth"
velacmd "github.com/oam-dev/kubevela/pkg/cmd"
cmdutil "github.com/oam-dev/kubevela/pkg/cmd/util"
"github.com/oam-dev/kubevela/pkg/utils/util"
)
// AuthCommandGroup commands for create resources or configuration
func AuthCommandGroup ( f velacmd . Factory , streams util . IOStreams ) * cobra . Command {
cmd := & cobra . Command {
Use : "auth" ,
Short : i18n . T ( "Manage identity and authorizations." ) ,
Annotations : map [ string ] string {
types . TagCommandType : types . TypeCD ,
} ,
}
cmd . AddCommand ( NewGenKubeConfigCommand ( f , streams ) )
2022-05-18 20:57:39 +08:00
cmd . AddCommand ( NewListPrivilegesCommand ( f , streams ) )
2022-05-18 16:14:00 +08:00
return cmd
}
// GenKubeConfigOptions options for create kubeconfig
type GenKubeConfigOptions struct {
2022-05-18 20:57:39 +08:00
auth . Identity
2022-05-18 16:14:00 +08:00
util . IOStreams
}
// Complete .
func ( opt * GenKubeConfigOptions ) Complete ( f velacmd . Factory , cmd * cobra . Command ) {
2022-05-18 20:57:39 +08:00
if opt . Identity . ServiceAccount != "" {
opt . Identity . ServiceAccountNamespace = velacmd . GetNamespace ( f , cmd )
2022-05-18 16:14:00 +08:00
}
2022-05-18 20:57:39 +08:00
opt . Regularize ( )
2022-05-18 16:14:00 +08:00
}
// Validate .
func ( opt * GenKubeConfigOptions ) Validate ( ) error {
2022-05-18 20:57:39 +08:00
return opt . Identity . Validate ( )
2022-05-18 16:14:00 +08:00
}
// Run .
func ( opt * GenKubeConfigOptions ) Run ( f velacmd . Factory ) error {
ctx := context . Background ( )
cli , err := kubernetes . NewForConfig ( f . Config ( ) )
if err != nil {
return err
}
cfg , err := clientcmd . NewDefaultPathOptions ( ) . GetStartingConfig ( )
if err != nil {
return err
}
2022-05-18 20:57:39 +08:00
cfg , err = auth . GenerateKubeConfig ( ctx , cli , cfg , opt . IOStreams . ErrOut , auth . KubeConfigWithIdentityGenerateOption ( opt . Identity ) )
2022-05-18 16:14:00 +08:00
if err != nil {
return err
}
bs , err := clientcmd . Write ( * cfg )
if err != nil {
return err
}
_ , err = opt . Out . Write ( bs )
return err
}
var (
genKubeConfigLong = templates . LongDesc ( i18n . T ( `
Generate kubeconfig for user
Generate a new kubeconfig with specified identity . By default , the generated kubeconfig
will reuse the certificate - authority - data in the cluster config from the current used
kubeconfig . All contexts , clusters and users that are not in use will not be included
in the generated kubeconfig .
To generate a new kubeconfig for given user and groups , use the -- user and -- group flag .
Multiple -- group flags is allowed . The group kubevela : client is added to the groups by
default . The identity in the current kubeconfig should be able to approve
CertificateSigningRequest in the kubernetes cluster . See
https : //kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/
for details .
To generate a kubeconfig based on existing ServiceAccount in your cluster , use the
-- serviceaccount flag . The corresponding secret token and ca data will be embedded in
the generated kubeconfig , which allows you to act as the serviceaccount . ` ) )
generateKubeConfigExample = templates . Examples ( i18n . T ( `
# Generate a kubeconfig with provided user
vela auth gen - kubeconfig -- user new - user
# Generate a kubeconfig with provided user and group
vela auth gen - kubeconfig -- user new - user -- group kubevela : developer
# Generate a kubeconfig with provided user and groups
vela auth gen - kubeconfig -- user new - user -- group kubevela : developer -- group my - org : my - team
# Generate a kubeconfig with provided serviceaccount
vela auth gen - kubeconfig -- serviceaccount default - n demo ` ) )
)
// NewGenKubeConfigCommand generate kubeconfig for given user and groups
func NewGenKubeConfigCommand ( f velacmd . Factory , streams util . IOStreams ) * cobra . Command {
o := & GenKubeConfigOptions { IOStreams : streams }
cmd := & cobra . Command {
Use : "gen-kubeconfig" ,
DisableFlagsInUseLine : true ,
Short : i18n . T ( "Generate kubeconfig for user" ) ,
Long : genKubeConfigLong ,
Example : generateKubeConfigExample ,
Annotations : map [ string ] string {
types . TagCommandType : types . TypeCD ,
} ,
Args : cobra . ExactValidArgs ( 0 ) ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
o . Complete ( f , cmd )
cmdutil . CheckErr ( o . Validate ( ) )
cmdutil . CheckErr ( o . Run ( f ) )
} ,
}
cmd . Flags ( ) . StringVarP ( & o . User , "user" , "u" , o . User , "The user of the generated kubeconfig. If set, an X509-based kubeconfig will be intended to create. It will be embedded as the Subject in the X509 certificate." )
cmd . Flags ( ) . StringSliceVarP ( & o . Groups , "group" , "g" , o . Groups , "The groups of the generated kubeconfig. This flag only works when `--user` is set. It will be embedded as the Organization in the X509 certificate." )
2022-05-18 20:57:39 +08:00
cmd . Flags ( ) . StringVarP ( & o . ServiceAccount , "serviceaccount" , "" , o . ServiceAccount , "The serviceaccount of the generated kubeconfig. If set, a kubeconfig will be generated based on the secret token of the serviceaccount. Cannot be set when `--user` presents." )
2022-05-18 16:14:00 +08:00
cmdutil . CheckErr ( cmd . RegisterFlagCompletionFunc (
"serviceaccount" , func ( cmd * cobra . Command , args [ ] string , toComplete string ) ( [ ] string , cobra . ShellCompDirective ) {
if strings . TrimSpace ( o . User ) != "" {
return nil , cobra . ShellCompDirectiveNoFileComp
}
namespace := velacmd . GetNamespace ( f , cmd )
return velacmd . GetServiceAccountForCompletion ( cmd . Context ( ) , f , namespace , toComplete )
} ) )
return velacmd . NewCommandBuilder ( f , cmd ) .
WithNamespaceFlag ( velacmd . NamespaceFlagUsageOption ( "The namespace of the serviceaccount. This flag only works when `--serviceaccount` is set." ) ) .
WithStreams ( streams ) .
WithResponsiveWriter ( ) .
Build ( )
}
2022-05-18 20:57:39 +08:00
// ListPrivilegesOptions options for list privileges
type ListPrivilegesOptions struct {
auth . Identity
KubeConfig string
Clusters [ ] string
util . IOStreams
}
// Complete .
func ( opt * ListPrivilegesOptions ) Complete ( f velacmd . Factory , cmd * cobra . Command ) {
if opt . KubeConfig != "" {
identity , err := auth . ReadIdentityFromKubeConfig ( opt . KubeConfig )
cmdutil . CheckErr ( err )
opt . Identity = * identity
}
if opt . Identity . ServiceAccount != "" {
opt . Identity . ServiceAccountNamespace = velacmd . GetNamespace ( f , cmd )
}
if len ( opt . Clusters ) == 0 {
opt . Clusters = [ ] string { types . ClusterLocalName }
}
opt . Regularize ( )
}
// Validate .
func ( opt * ListPrivilegesOptions ) Validate ( f velacmd . Factory , cmd * cobra . Command ) error {
if err := opt . Identity . Validate ( ) ; err != nil {
return err
}
for _ , cluster := range opt . Clusters {
if _ , err := prismclusterv1alpha1 . NewClusterClient ( f . Client ( ) ) . Get ( cmd . Context ( ) , cluster ) ; err != nil {
return fmt . Errorf ( "failed to find cluster %s: %w" , cluster , err )
}
}
return nil
}
// Run .
func ( opt * ListPrivilegesOptions ) Run ( f velacmd . Factory ) error {
ctx := context . Background ( )
m , err := auth . ListPrivileges ( ctx , f . Client ( ) , opt . Clusters , & opt . Identity )
if err != nil {
return err
}
width , _ , err := term . GetSize ( 0 )
if err != nil {
width = 80
}
_ , _ = opt . Out . Write ( [ ] byte ( auth . PrettyPrintPrivileges ( & opt . Identity , m , opt . Clusters , uint ( width ) - 40 ) ) )
return nil
}
var (
listPrivilegesLong = templates . LongDesc ( i18n . T ( `
List privileges for user
List privileges that user has in clusters . Use -- user / -- group to check the privileges
for specified user and group . They can be jointly configured to see the union of
privileges . Use -- serviceaccount and - n / -- namespace to see the privileges for
ServiceAccount . You can also use -- kubeconfig to use the identity inside implicitly .
The privileges will be shown in tree format .
This command supports listing privileges across multiple clusters , by using -- cluster .
If not set , the control plane will be used . This feature requires cluster - gateway to be
properly setup to use .
The privileges are collected through listing all ClusterRoleBinding and RoleBinding ,
following the Kubernetes RBAC Authorization . Other authorization mechanism is not supported
now . See https : //kubernetes.io/docs/reference/access-authn-authz/rbac/ for details.
The ClusterRoleBinding and RoleBinding that matches the specified identity will be
tracked . Related ClusterRoles and Roles are retrieved and the contained PolicyRules are
demonstrated . ` ) )
listPrivilegesExample = templates . Examples ( i18n . T ( `
# List privileges for User alice in the control plane
vela auth list - privileges -- user alice
# List privileges for Group org : dev - team in the control plane
vela auth list - privileges -- group org : dev - team
# List privileges for User bob with Groups org : dev - team and org : test - team in the control plane and managed cluster example - cluster
vela auth list - privileges -- user bob -- group org : dev - team -- group org : test - team -- cluster local -- cluster example - cluster
# List privileges for ServiceAccount example - sa in demo namespace in multiple managed clusters
vela auth list - privileges -- serviceaccount example - sa - n demo -- cluster cluster - 1 -- cluster cluster - 2
# List privileges for identity in kubeconfig
vela auth list - privileges -- kubeconfig . / example . kubeconfig -- cluster local -- cluster cluster - 1 ` ) )
)
// NewListPrivilegesCommand list privileges for given identity
func NewListPrivilegesCommand ( f velacmd . Factory , streams util . IOStreams ) * cobra . Command {
o := & ListPrivilegesOptions { IOStreams : streams }
cmd := & cobra . Command {
Use : "list-privileges" ,
DisableFlagsInUseLine : true ,
Short : i18n . T ( "List privileges for user/group/serviceaccount" ) ,
Long : listPrivilegesLong ,
Example : listPrivilegesExample ,
Annotations : map [ string ] string {
types . TagCommandType : types . TypeCD ,
} ,
Args : cobra . ExactValidArgs ( 0 ) ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
o . Complete ( f , cmd )
cmdutil . CheckErr ( o . Validate ( f , cmd ) )
cmdutil . CheckErr ( o . Run ( f ) )
} ,
}
cmd . Flags ( ) . StringVarP ( & o . User , "user" , "u" , o . User , "The user to list privileges." )
cmd . Flags ( ) . StringSliceVarP ( & o . Groups , "group" , "g" , o . Groups , "The group to list privileges. Can be set together with --user." )
cmd . Flags ( ) . StringVarP ( & o . ServiceAccount , "serviceaccount" , "" , o . ServiceAccount , "The serviceaccount to list privileges. Cannot be set with --user and --group." )
cmd . Flags ( ) . StringSliceVarP ( & o . Clusters , "cluster" , "c" , o . Clusters , "The cluster to list privileges. If not set, the command will list privileges in the control plane." )
cmd . Flags ( ) . StringVarP ( & o . KubeConfig , "kubeconfig" , "" , o . KubeConfig , "The kubeconfig to list privileges. If set, it will override all the other identity flags." )
cmdutil . CheckErr ( cmd . RegisterFlagCompletionFunc (
"serviceaccount" , func ( cmd * cobra . Command , args [ ] string , toComplete string ) ( [ ] string , cobra . ShellCompDirective ) {
if strings . TrimSpace ( o . User ) != "" {
return nil , cobra . ShellCompDirectiveNoFileComp
}
namespace := velacmd . GetNamespace ( f , cmd )
return velacmd . GetServiceAccountForCompletion ( cmd . Context ( ) , f , namespace , toComplete )
} ) )
cmdutil . CheckErr ( cmd . RegisterFlagCompletionFunc (
"cluster" , func ( cmd * cobra . Command , args [ ] string , toComplete string ) ( [ ] string , cobra . ShellCompDirective ) {
return velacmd . GetClustersForCompletion ( cmd . Context ( ) , f , toComplete )
} ) )
return velacmd . NewCommandBuilder ( f , cmd ) .
WithNamespaceFlag ( velacmd . NamespaceFlagUsageOption ( "The namespace of the serviceaccount. This flag only works when `--serviceaccount` is set." ) ) .
WithStreams ( streams ) .
WithResponsiveWriter ( ) .
Build ( )
}