Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/stackit_ske.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ stackit ske [flags]
* [stackit ske describe](./stackit_ske_describe.md) - Shows overall details regarding SKE
* [stackit ske disable](./stackit_ske_disable.md) - Disables SKE for a project
* [stackit ske enable](./stackit_ske_enable.md) - Enables SKE for a project
* [stackit ske kubeconfig](./stackit_ske_kubeconfig.md) - Provides functionality for SKE kubeconfig
* [stackit ske options](./stackit_ske_options.md) - Lists SKE provider options

1 change: 1 addition & 0 deletions docs/stackit_ske_credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ stackit ske credentials [flags]
### SEE ALSO

* [stackit ske](./stackit_ske.md) - Provides functionality for SKE
* [stackit ske credentials complete-rotation](./stackit_ske_credentials_complete-rotation.md) - Completes the rotation of the credentials associated to a SKE cluster
* [stackit ske credentials describe](./stackit_ske_credentials_describe.md) - Shows details of the credentials associated to a SKE cluster
* [stackit ske credentials rotate](./stackit_ske_credentials_rotate.md) - Rotates credentials associated to a SKE cluster
* [stackit ske credentials start-rotation](./stackit_ske_credentials_start-rotation.md) - Starts the rotation of the credentials associated to a SKE cluster
Expand Down
52 changes: 52 additions & 0 deletions docs/stackit_ske_credentials_complete-rotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## stackit ske credentials complete-rotation

Completes the rotation of the credentials associated to a SKE cluster

### Synopsis

Completes the rotation of the credentials associated to a STACKIT Kubernetes Engine (SKE) cluster.
To ensure continued access to the Kubernetes cluster, please update your kubeconfig service account to the newly created account.
This is step 2 of a 2-step process to rotate all SKE cluster credentials. Tasks accomplished in this phase include:
- The old certification authority will be dropped from the package.
- The old signing key for the service account will be dropped from the bundle.

If you haven't, please start the process by running:
$ stackit ske credentials start-rotation my-cluster
After completing the rotation of credentials, you can generate a new kubeconfig file by running:
$ stackit ske kubeconfig create my-cluster

```
stackit ske credentials complete-rotation CLUSTER_NAME [flags]
```

### Examples

```
Complete the rotation of the credentials associated to the SKE cluster with name "my-cluster"
$ stackit ske credentials complete-rotation my-cluster

Flow of the 2-step process to rotate all SKE cluster credentials, including generating a new kubeconfig file
$ stackit ske credentials start-rotation my-cluster
$ stackit ske credentials complete-rotation my-cluster
$ stackit ske kubeconfig create my-cluster
```

### Options

```
-h, --help Help for "stackit ske credentials complete-rotation"
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty"]
-p, --project-id string Project ID
```

### SEE ALSO

* [stackit ske credentials](./stackit_ske_credentials.md) - Provides functionality for SKE credentials

18 changes: 16 additions & 2 deletions docs/stackit_ske_credentials_start-rotation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@ Starts the rotation of the credentials associated to a SKE cluster

### Synopsis

Starts the rotation of the credentials associated to a STACKIT Kubernetes Engine (SKE) cluster. This is step 1 of a two-step process.
Complete the rotation using the 'stackit ske credentials complete-rotation' command.
Starts the rotation of the credentials associated to a STACKIT Kubernetes Engine (SKE) cluster.
This is step 1 of a 2-step process to rotate all SKE cluster credentials. Tasks accomplished in this phase include:
- Rolling recreation of all worker nodes
- A new Certificate Authority (CA) will be established and incorporated into the existing CA bundle.
- A new etcd encryption key is generated and added to the Certificate Authority (CA) bundle.
- A new signing key will be generated for the service account and added to the Certificate Authority (CA) bundle.
- The kube-apiserver will rewrite all secrets in the cluster, encrypting them with the new encryption key.
The old CA, encryption key and signing key will be retained until the rotation is completed.

Complete the rotation by running:
$ stackit ske credentials complete-rotation my-cluster

```
stackit ske credentials start-rotation CLUSTER_NAME [flags]
Expand All @@ -16,6 +25,11 @@ stackit ske credentials start-rotation CLUSTER_NAME [flags]
```
Start the rotation of the credentials associated to the SKE cluster with name "my-cluster"
$ stackit ske credentials start-rotation my-cluster

Flow of the 2-step process to rotate all SKE cluster credentials, including generating a new kubeconfig file
$ stackit ske credentials start-rotation my-cluster
$ stackit ske credentials complete-rotation my-cluster
$ stackit ske kubeconfig create my-cluster
```

### Options
Expand Down
32 changes: 32 additions & 0 deletions docs/stackit_ske_kubeconfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## stackit ske kubeconfig

Provides functionality for SKE kubeconfig

### Synopsis

Provides functionality for STACKIT Kubernetes Engine (SKE) kubeconfig.

```
stackit ske kubeconfig [flags]
```

### Options

```
-h, --help Help for "stackit ske kubeconfig"
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty"]
-p, --project-id string Project ID
```

### SEE ALSO

* [stackit ske](./stackit_ske.md) - Provides functionality for SKE
* [stackit ske kubeconfig create](./stackit_ske_kubeconfig_create.md) - Creates a kubeconfig for an SKE cluster

50 changes: 50 additions & 0 deletions docs/stackit_ske_kubeconfig_create.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## stackit ske kubeconfig create

Creates a kubeconfig for an SKE cluster

### Synopsis

Creates a kubeconfig for a STACKIT Kubernetes Engine (SKE) cluster.
By default the kubeconfig is created in the .kube folder, in the user's home directory. The kubeconfig file will be overwritten if it already exists.

```
stackit ske kubeconfig create CLUSTER_NAME [flags]
```

### Examples

```
Create a kubeconfig for the SKE cluster with name "my-cluster"
$ stackit ske kubeconfig create my-cluster

Create a kubeconfig for the SKE cluster with name "my-cluster" and set the expiration time to 30 days
$ stackit ske kubeconfig create my-cluster --expiration 30d

Create a kubeconfig for the SKE cluster with name "my-cluster" and set the expiration time to 2 months
$ stackit ske kubeconfig create my-cluster --expiration 2M

Create a kubeconfig for the SKE cluster with name "my-cluster" in a custom location
$ stackit ske kubeconfig create my-cluster --location /path/to/config
```

### Options

```
-e, --expiration string Expiration time for the kubeconfig in seconds(s), minutes(m), hours(h), days(d) or months(M). Example: 30d. By default, expiration time is 1h
-h, --help Help for "stackit ske kubeconfig create"
--location string Folder location to store the kubeconfig file. By default, the kubeconfig is created in the .kube folder, in the user's home directory.
```

### Options inherited from parent commands

```
-y, --assume-yes If set, skips all confirmation prompts
--async If set, runs the command asynchronously
-o, --output-format string Output format, one of ["json" "pretty"]
-p, --project-id string Project ID
```

### SEE ALSO

* [stackit ske kubeconfig](./stackit_ske_kubeconfig.md) - Provides functionality for SKE kubeconfig

152 changes: 152 additions & 0 deletions internal/cmd/ske/kubeconfig/create/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package create

import (
"context"
"fmt"

"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/confirm"
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/client"
skeUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/utils"

"github.com/spf13/cobra"
"github.com/stackitcloud/stackit-sdk-go/services/ske"
)

const (
clusterNameArg = "CLUSTER_NAME"

expirationFlag = "expiration"
locationFlag = "location"
)

type inputModel struct {
*globalflags.GlobalFlagModel
ClusterName string
Location *string
ExpirationTime *string
}

func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("create %s", clusterNameArg),
Short: "Creates a kubeconfig for an SKE cluster",
Long: fmt.Sprintf("%s\n%s",
"Creates a kubeconfig for a STACKIT Kubernetes Engine (SKE) cluster.",
"By default the kubeconfig is created in the .kube folder, in the user's home directory. The kubeconfig file will be overwritten if it already exists."),
Args: args.SingleArg(clusterNameArg, nil),
Example: examples.Build(
examples.NewExample(
`Create a kubeconfig for the SKE cluster with name "my-cluster"`,
"$ stackit ske kubeconfig create my-cluster"),
examples.NewExample(
`Create a kubeconfig for the SKE cluster with name "my-cluster" and set the expiration time to 30 days`,
"$ stackit ske kubeconfig create my-cluster --expiration 30d"),
examples.NewExample(
`Create a kubeconfig for the SKE cluster with name "my-cluster" and set the expiration time to 2 months`,
"$ stackit ske kubeconfig create my-cluster --expiration 2M"),
examples.NewExample(
`Create a kubeconfig for the SKE cluster with name "my-cluster" in a custom location`,
"$ stackit ske kubeconfig create my-cluster --location /path/to/config"),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(cmd, args)
if err != nil {
return err
}

// Configure API client
apiClient, err := client.ConfigureClient(cmd)
if err != nil {
return err
}

if !model.AssumeYes {
prompt := fmt.Sprintf("Are you sure you want to create a kubeconfig for SKE cluster %q? This will OVERWRITE your current configuration, if it exists.", model.ClusterName)
err = confirm.PromptForConfirmation(cmd, prompt)
if err != nil {
return err
}
}

// Call API
req, err := buildRequest(ctx, model, apiClient)
if err != nil {
return fmt.Errorf("build kubeconfig create request: %w", err)
}
resp, err := req.Execute()
if err != nil {
return fmt.Errorf("create kubeconfig for SKE cluster: %w", err)
}

// Create the config file
if resp.Kubeconfig == nil {
return fmt.Errorf("no kubeconfig returned from the API")
}

var kubeconfigPath string
if model.Location == nil {
kubeconfigPath, err = skeUtils.GetDefaultKubeconfigLocation()
if err != nil {
return fmt.Errorf("get default kubeconfig location: %w", err)
}
} else {
kubeconfigPath = *model.Location
}

err = skeUtils.WriteConfigFile(kubeconfigPath, *resp.Kubeconfig)
if err != nil {
return fmt.Errorf("write kubeconfig file: %w", err)
}

fmt.Printf("Created kubeconfig file for cluster %s in %q, with expiration date %v (UTC)\n", model.ClusterName, kubeconfigPath, *resp.ExpirationTimestamp)

return nil
},
}
configureFlags(cmd)
return cmd
}

func configureFlags(cmd *cobra.Command) {
cmd.Flags().StringP(expirationFlag, "e", "", "Expiration time for the kubeconfig in seconds(s), minutes(m), hours(h), days(d) or months(M). Example: 30d. By default, expiration time is 1h")
cmd.Flags().String(locationFlag, "", "Folder location to store the kubeconfig file. By default, the kubeconfig is created in the .kube folder, in the user's home directory.")
}

func parseInput(cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
clusterName := inputArgs[0]

globalFlags := globalflags.Parse(cmd)
if globalFlags.ProjectId == "" {
return nil, &errors.ProjectIdError{}
}

return &inputModel{
GlobalFlagModel: globalFlags,
ClusterName: clusterName,
Location: flags.FlagToStringPointer(cmd, locationFlag),
ExpirationTime: flags.FlagToStringPointer(cmd, expirationFlag),
}, nil
}

func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClient) (ske.ApiCreateKubeconfigRequest, error) {
req := apiClient.CreateKubeconfig(ctx, model.ProjectId, model.ClusterName)

payload := ske.CreateKubeconfigPayload{}

if model.ExpirationTime != nil {
expirationTime, err := skeUtils.ConvertToSeconds(*model.ExpirationTime)
if err != nil {
return req, fmt.Errorf("parse expiration time: %w", err)
}

payload.ExpirationSeconds = expirationTime
}

return req.CreateKubeconfigPayload(payload), nil
}
Loading