diff --git a/docs/cli/getting-started.md b/docs/cli/getting-started.md index 46232bcff..43667e318 100644 --- a/docs/cli/getting-started.md +++ b/docs/cli/getting-started.md @@ -20,10 +20,10 @@ of Kubernetes workloads deployed in your cluster. To begin with, execute the following one-time setup command: ``` -starboard init +starboard install ``` -The `init` subcommand creates the `starboard` namespace, in which Starboard executes Kubernetes jobs to perform +The `install` subcommand creates the `starboard` namespace, in which Starboard executes Kubernetes jobs to perform scans. It also sends custom security resources definitions to the Kubernetes API: ```console @@ -36,7 +36,7 @@ vulnerabilityreports vulns,vuln aquasecurity.github.io true Vulne ``` !!! tip - There's also a `starboard cleanup` subcommand, which can be used to remove all resources created by Starboard. + There's also a `starboard uninstall` subcommand, which can be used to remove all resources created by Starboard. As an example let's run in the current namespace an old version of `nginx` that we know has vulnerabilities: diff --git a/embedded.go b/embedded.go index 8fce55697..f650d9573 100644 --- a/embedded.go +++ b/embedded.go @@ -10,6 +10,8 @@ import ( var ( //go:embed deploy/crd/vulnerabilityreports.crd.yaml vulnerabilityReportsCRD []byte + //go:embed deploy/crd/clustervulnerabilityreports.crd.yaml + clusterVulnerabilityReportsCRD []byte //go:embed deploy/crd/configauditreports.crd.yaml configAuditReportsCRD []byte //go:embed deploy/crd/clusterconfigauditreports.crd.yaml @@ -24,6 +26,10 @@ func GetVulnerabilityReportsCRD() (apiextensionsv1.CustomResourceDefinition, err return getCRDFromBytes(vulnerabilityReportsCRD) } +func GetClusterVulnerabilityReportsCRD() (apiextensionsv1.CustomResourceDefinition, error) { + return getCRDFromBytes(clusterVulnerabilityReportsCRD) +} + func GetConfigAuditReportsCRD() (apiextensionsv1.CustomResourceDefinition, error) { return getCRDFromBytes(configAuditReportsCRD) } diff --git a/itest/starboard/starboard_cli_test.go b/itest/starboard/starboard_cli_test.go index bb4e9f24f..e07481d6c 100644 --- a/itest/starboard/starboard_cli_test.go +++ b/itest/starboard/starboard_cli_test.go @@ -35,13 +35,13 @@ var _ = Describe("Starboard CLI", func() { BeforeEach(func() { err := cmd.Run(versionInfo, []string{ - "starboard", "init", + "starboard", "install", "-v", starboardCLILogLevel, }, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) }) - Describe("Command init", func() { + Describe("Command install", func() { It("should initialize Starboard", func() { @@ -68,6 +68,21 @@ var _ = Describe("Starboard CLI", func() { "Scope": Equal(apiextensionsv1beta1.NamespaceScoped), }), }), + "clustervulnerabilityreports.aquasecurity.github.io": MatchFields(IgnoreExtras, Fields{ + "Spec": MatchFields(IgnoreExtras, Fields{ + "Group": Equal("aquasecurity.github.io"), + "Version": Equal("v1alpha1"), + "Names": Equal(apiextensionsv1beta1.CustomResourceDefinitionNames{ + Plural: "clustervulnerabilityreports", + Singular: "clustervulnerabilityreport", + ShortNames: []string{"clustervuln", "clustervulns"}, + Kind: "ClusterVulnerabilityReport", + ListKind: "ClusterVulnerabilityReportList", + Categories: []string{"all"}, + }), + "Scope": Equal(apiextensionsv1beta1.ClusterScoped), + }), + }), "configauditreports.aquasecurity.github.io": MatchFields(IgnoreExtras, Fields{ "Spec": MatchFields(IgnoreExtras, Fields{ "Group": Equal("aquasecurity.github.io"), @@ -630,7 +645,7 @@ var _ = Describe("Starboard CLI", func() { }) }) - Describe("Command get vulnerabilities", func() { + Describe("Command get vulnerabilityreports", func() { Context("for deployment/nginx resource", func() { When("vulnerabilities are associated with the deployment itself", func() { @@ -662,7 +677,7 @@ var _ = Describe("Starboard CLI", func() { stderr := NewBuffer() err := cmd.Run(versionInfo, []string{ - "starboard", "get", "vulnerabilities", + "starboard", "get", "vulnerabilityreports", "deployment/" + deploy.Name, "--namespace", deploy.Namespace, "-v", starboardCLILogLevel, @@ -1107,7 +1122,7 @@ var _ = Describe("Starboard CLI", func() { AfterEach(func() { err := cmd.Run(versionInfo, []string{ "starboard", - "cleanup", + "uninstall", "-v", starboardCLILogLevel, }, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/apis/aquasecurity/v1alpha1/vulnerability_types.go b/pkg/apis/aquasecurity/v1alpha1/vulnerability_types.go index 81a560de5..f25aaa9d0 100644 --- a/pkg/apis/aquasecurity/v1alpha1/vulnerability_types.go +++ b/pkg/apis/aquasecurity/v1alpha1/vulnerability_types.go @@ -9,6 +9,8 @@ const ( VulnerabilityReportsCRVersion = "v1alpha1" VulnerabilityReportKind = "VulnerabilityReport" VulnerabilityReportListKind = "VulnerabilityReportList" + + ClusterVulnerabilityReportsCRName = "clustervulnerabilityreports.aquasecurity.github.io" ) type Severity string diff --git a/pkg/cmd/cleanup.go b/pkg/cmd/cleanup.go index 6471dca3d..50a1fc874 100644 --- a/pkg/cmd/cleanup.go +++ b/pkg/cmd/cleanup.go @@ -13,8 +13,9 @@ import ( func NewCleanupCmd(buildInfo starboard.BuildInfo, cf *genericclioptions.ConfigFlags) *cobra.Command { cmd := &cobra.Command{ - Use: "cleanup", - Short: "Delete Kubernetes resources created by Starboard", + Use: "uninstall", + Aliases: []string{"cleanup"}, + Short: "Delete Kubernetes resources created by Starboard", RunE: func(cmd *cobra.Command, args []string) error { kubeConfig, err := cf.ToRESTConfig() if err != nil { diff --git a/pkg/cmd/init.go b/pkg/cmd/init.go index 7be0d29c1..516f6aa06 100644 --- a/pkg/cmd/init.go +++ b/pkg/cmd/init.go @@ -13,14 +13,17 @@ import ( func NewInitCmd(buildInfo starboard.BuildInfo, cf *genericclioptions.ConfigFlags) *cobra.Command { cmd := &cobra.Command{ - Use: "init", - Short: "Create Kubernetes resources used by Starboard", + Use: "install", + Aliases: []string{"init"}, + Short: "Create Kubernetes resources used by Starboard", Long: `Create all the resources used by Starboard. It will create the following in your Kubernetes cluster: - CustomResourceDefinition objects: - "vulnerabilityreports.aquasecurity.github.io" + - "clustervulnerabilityreports.aquasecurity.github.io" - "configauditreports.aquasecurity.github.io" + - "clusterconfigauditreports.aquasecurity.github.io" - "ciskubebenchreports.aquasecurity.github.io" - "kubehunterreports.aquasecurity.github.io" - RBAC objects: @@ -30,13 +33,15 @@ Kubernetes cluster: - The "starboard" service account - The "starboard" ConfigMap - The "starboard" secret + - The "starboard-trivy-config" ConfigMap + - The "starboard-polaris-config" ConfigMap The "starboard" ConfigMap and the "starboard" secret contain the default config parameters. However this can be modified to change the behaviour of the scanners. All resources created by this command can be removed from the cluster using -the "cleanup" command.`, +the "uninstall" command.`, RunE: func(cmd *cobra.Command, args []string) error { kubeConfig, err := cf.ToRESTConfig() if err != nil { diff --git a/pkg/cmd/installer.go b/pkg/cmd/installer.go index 403b54731..350b72da6 100644 --- a/pkg/cmd/installer.go +++ b/pkg/cmd/installer.go @@ -32,7 +32,7 @@ var ( ObjectMeta: metav1.ObjectMeta{ Name: starboard.NamespaceName, Labels: labels.Set{ - "app.kubernetes.io/managed-by": "starboard", + starboard.LabelK8SAppManagedBy: "starboard", }, }, } @@ -40,7 +40,7 @@ var ( ObjectMeta: metav1.ObjectMeta{ Name: starboard.ServiceAccountName, Labels: labels.Set{ - "app.kubernetes.io/managed-by": "starboard", + starboard.LabelK8SAppManagedBy: "starboard", }, }, AutomountServiceAccountToken: pointer.BoolPtr(false), @@ -49,7 +49,7 @@ var ( ObjectMeta: metav1.ObjectMeta{ Name: clusterRoleStarboard, Labels: labels.Set{ - "app.kubernetes.io/managed-by": "starboard", + starboard.LabelK8SAppManagedBy: "starboard", }, }, Rules: []rbacv1.PolicyRule{ @@ -102,7 +102,7 @@ var ( ObjectMeta: metav1.ObjectMeta{ Name: clusterRoleBindingStarboard, Labels: labels.Set{ - "app.kubernetes.io/managed-by": "starboard", + starboard.LabelK8SAppManagedBy: "starboard", }, }, RoleRef: rbacv1.RoleRef{ @@ -155,7 +155,14 @@ func (m *Installer) Install(ctx context.Context) error { if err != nil { return err } - + clusterVulnerabilityReportsCRD, err := embedded.GetClusterVulnerabilityReportsCRD() + if err != nil { + return err + } + err = m.createOrUpdateCRD(ctx, &clusterVulnerabilityReportsCRD) + if err != nil { + return err + } kubeBenchReportsCRD, err := embedded.GetCISKubeBenchReportsCRD() if err != nil { return err @@ -395,6 +402,10 @@ func (m *Installer) Uninstall(ctx context.Context) error { if err != nil { return err } + err = m.deleteCRD(ctx, v1alpha1.ClusterVulnerabilityReportsCRName) + if err != nil { + return err + } err = m.deleteCRD(ctx, v1alpha1.CISKubeBenchReportCRName) if err != nil { return err diff --git a/pkg/cmd/get_report.go b/pkg/cmd/report.go similarity index 86% rename from pkg/cmd/get_report.go rename to pkg/cmd/report.go index dc736b109..d04d32a37 100644 --- a/pkg/cmd/get_report.go +++ b/pkg/cmd/report.go @@ -13,7 +13,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -func NewGetReportCmd(info starboard.BuildInfo, cf *genericclioptions.ConfigFlags, outWriter io.Writer) *cobra.Command { +func NewReportCmd(info starboard.BuildInfo, cf *genericclioptions.ConfigFlags, out io.Writer) *cobra.Command { return &cobra.Command{ Use: "report (NAME | TYPE/NAME)", Short: "Generate an HTML security report for a specified Kubernetes object", @@ -40,13 +40,13 @@ TYPE is a Kubernetes workload. Shortcuts and API groups will be resolved, e.g. ' NAME is the name of a particular Kubernetes workload. `, info.Executable), Example: fmt.Sprintf(` # Generate an HTML report for a deployment with the specified name and save it to a file. - %[1]s get report deployment/nginx > nginx.deploy.html + %[1]s report deployment/nginx > nginx.deploy.html # Generate an HTML report for a namespace with the specified name and save it to a file. - %[1]s get report namespace/kube-system > kube-system.ns.html + %[1]s report namespace/kube-system > kube-system.ns.html # Generate an HTML report for a node with the specified name and save it to a file. - %[1]s get report node/kind-control-plane > kind-control-plane.node.html + %[1]s report node/kind-control-plane > kind-control-plane.node.html `, info.Executable), RunE: func(cmd *cobra.Command, args []string) error { kubeConfig, err := cf.ToRESTConfig() @@ -77,13 +77,13 @@ NAME is the name of a particular Kubernetes workload. kube.KindJob, kube.KindPod: reporter := report.NewWorkloadReporter(clock, kubeClient) - return reporter.Generate(workload, outWriter) + return reporter.Generate(workload, out) case kube.KindNamespace: reporter := report.NewNamespaceReporter(clock, kubeClient) - return reporter.Generate(workload, outWriter) + return reporter.Generate(workload, out) case kube.KindNode: reporter := report.NewNodeReporter(clock, kubeClient) - return reporter.Generate(workload, outWriter) + return reporter.Generate(workload, out) default: return fmt.Errorf("HTML report is not supported for %q", workload.Kind) } diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go index 3915a33aa..6efb3145a 100644 --- a/pkg/cmd/root.go +++ b/pkg/cmd/root.go @@ -55,7 +55,7 @@ func NewRootCmd(buildInfo starboard.BuildInfo, args []string, outWriter io.Write rootCmd.AddCommand(NewInitCmd(buildInfo, cf)) rootCmd.AddCommand(NewScanCmd(buildInfo, cf)) rootCmd.AddCommand(NewGetCmd(buildInfo, cf, outWriter)) - rootCmd.AddCommand(NewGetReportCmd(buildInfo, cf, outWriter)) + rootCmd.AddCommand(NewReportCmd(buildInfo, cf, outWriter)) rootCmd.AddCommand(NewCleanupCmd(buildInfo, cf)) rootCmd.AddCommand(NewConfigCmd(cf, outWriter))