Skip to content

Commit

Permalink
fix: fix the use of a hardcoded admin user
Browse files Browse the repository at this point in the history
The terraform provider code used a hardcoded `admin` user in a number of place, which caused issues
if a different username (or client credentails) was used. With this change we use the username (or
clientID) as specified in the provider.

This PR also changes the username that is passed in arguments to SSH key management calls. Juju
3.6 currently ignores the user passed in the arguments and always adds the key for the
logged-in user. For consistency we pass in the username that is used to log in to the
controller. This might change in Juju 4.
  • Loading branch information
alesstimec committed Jan 15, 2025
1 parent fbd1ccc commit 575152c
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 20 deletions.
35 changes: 25 additions & 10 deletions internal/juju/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"time"

Expand All @@ -21,15 +22,16 @@ import (
)

const (
PrefixCloud = "cloud-"
PrefixModel = "model-"
PrefixCharm = "charm-"
PrefixUser = "user-"
PrefixMachine = "machine-"
PrefixApplication = "application-"
PrefixStorage = "storage-"
UnspecifiedRevision = -1
connectionTimeout = 30 * time.Second
PrefixCloud = "cloud-"
PrefixModel = "model-"
PrefixCharm = "charm-"
PrefixUser = "user-"
PrefixMachine = "machine-"
PrefixApplication = "application-"
PrefixStorage = "storage-"
UnspecifiedRevision = -1
connectionTimeout = 30 * time.Second
serviceAccountSuffix = "@serviceaccount"
)

type ControllerConfiguration struct {
Expand All @@ -54,7 +56,8 @@ type Client struct {
Secrets secretsClient
Jaas jaasClient

isJAAS func() bool
isJAAS func() bool
username string
}

// IsJAAS returns a boolean to indicate whether the controller configured is a JAAS controller.
Expand All @@ -63,6 +66,12 @@ func (c Client) IsJAAS() bool {
return c.isJAAS()
}

// Username returns the username specified in the Juju provider or, if specified, the
// service account username.
func (c Client) Username() string {
return c.username
}

type jujuModel struct {
name string
modelType model.ModelType
Expand Down Expand Up @@ -104,6 +113,11 @@ func NewClient(ctx context.Context, config ControllerConfiguration) (*Client, er
defaultJAASCheck = true
}

user := config.Username
if config.ClientID != "" && !strings.HasSuffix(config.ClientID, serviceAccountSuffix) {
user = fmt.Sprintf("%s%s", config.ClientID, serviceAccountSuffix)
}

return &Client{
Applications: *newApplicationClient(sc),
Clouds: *newKubernetesCloudsClient(sc),
Expand All @@ -117,6 +131,7 @@ func NewClient(ctx context.Context, config ControllerConfiguration) (*Client, er
Secrets: *newSecretsClient(sc),
Jaas: *newJaasClient(sc),
isJAAS: func() bool { return sc.IsJAAS(defaultJAASCheck) },
username: user,
}, nil
}

Expand Down
4 changes: 3 additions & 1 deletion internal/juju/offers.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type CreateOfferInput struct {
Endpoint string
ModelName string
ModelOwner string
OfferOwner string
Name string
}

Expand Down Expand Up @@ -117,7 +118,8 @@ func (c offersClient) CreateOffer(input *CreateOfferInput) (*CreateOfferResponse
if err != nil {
return nil, append(errs, err)
}
result, err := client.Offer(modelUUID, input.ApplicationName, []string{input.Endpoint}, "admin", offerName, "")

result, err := client.Offer(modelUUID, input.ApplicationName, []string{input.Endpoint}, input.OfferOwner, offerName, "")
if err != nil {
return nil, append(errs, err)
}
Expand Down
22 changes: 13 additions & 9 deletions internal/juju/sshKeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ type sshKeysClient struct {
}

type CreateSSHKeyInput struct {
Username string
ModelName string
Payload string
}

type ReadSSHKeyInput struct {
Username string
ModelName string
KeyIdentifier string
}
Expand All @@ -32,6 +34,7 @@ type ReadSSHKeyOutput struct {
}

type DeleteSSHKeyInput struct {
Username string
ModelName string
KeyIdentifier string
}
Expand All @@ -51,9 +54,9 @@ func (c *sshKeysClient) CreateSSHKey(input *CreateSSHKeyInput) error {

client := keymanager.NewClient(conn)

// NOTE
// Juju only stores ssh keys at a global level.
params, err := client.AddKeys("admin", input.Payload)
// NOTE: In Juju 3.6 ssh keys are not associated with user - they are global per model. We pass in
// the logged-in user for completeness. In Juju 4 ssh keys will be associated with users.<
params, err := client.AddKeys(input.Username, input.Payload)
if err != nil {
return err
}
Expand Down Expand Up @@ -83,9 +86,9 @@ func (c *sshKeysClient) ReadSSHKey(input *ReadSSHKeyInput) (*ReadSSHKeyOutput, e

client := keymanager.NewClient(conn)

// NOTE: At this moment Juju only uses global ssh keys.
// We hardcode the user to be admin.
returnedKeys, err := client.ListKeys(ssh.FullKeys, "admin")
// NOTE: In Juju 3.6 ssh keys are not associated with user - they are global per model. We pass in
// the logged-in user for completeness. In Juju 4 ssh keys will be associated with users.<
returnedKeys, err := client.ListKeys(ssh.FullKeys, input.Username)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -118,7 +121,7 @@ func (c *sshKeysClient) DeleteSSHKey(input *DeleteSSHKeyInput) error {
// that impacts the current Juju logic. As a temporal workaround
// we will check if this is the latest SSH key of this model and
// skip the delete.
returnedKeys, err := client.ListKeys(ssh.FullKeys, "admin")
returnedKeys, err := client.ListKeys(ssh.FullKeys, input.Username)
if err != nil {
return err
}
Expand All @@ -132,8 +135,9 @@ func (c *sshKeysClient) DeleteSSHKey(input *DeleteSSHKeyInput) error {
}
}

// NOTE: Right now Juju uses global users for keys
params, err := client.DeleteKeys("admin", input.KeyIdentifier)
// NOTE: In Juju 3.6 ssh keys are not associated with user - they are global per model. We pass in
// the logged-in user for completeness. In Juju 4 ssh keys will be associated with users.<
params, err := client.DeleteKeys(input.Username, input.KeyIdentifier)
if len(params) != 0 {
messages := make([]string, 0)
for _, e := range params {
Expand Down
1 change: 1 addition & 0 deletions internal/provider/resource_offer.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func (o *offerResource) Create(ctx context.Context, req resource.CreateRequest,
Name: offerName,
ApplicationName: plan.ApplicationName.ValueString(),
Endpoint: plan.EndpointName.ValueString(),
OfferOwner: o.client.Username(),
})
if errs != nil {
// TODO 10-Aug-2023
Expand Down
5 changes: 5 additions & 0 deletions internal/provider/resource_ssh_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func (s *sshKeyResource) Create(ctx context.Context, req resource.CreateRequest,
modelName := plan.ModelName.ValueString()

if err := s.client.SSHKeys.CreateSSHKey(&juju.CreateSSHKeyInput{
Username: s.client.Username(),
ModelName: modelName,
Payload: payload,
}); err != nil {
Expand Down Expand Up @@ -173,6 +174,7 @@ func (s *sshKeyResource) Read(ctx context.Context, req resource.ReadRequest, res
}

result, err := s.client.SSHKeys.ReadSSHKey(&juju.ReadSSHKeyInput{
Username: s.client.Username(),
ModelName: modelName,
KeyIdentifier: keyIdentifier,
})
Expand Down Expand Up @@ -221,6 +223,7 @@ func (s *sshKeyResource) Update(ctx context.Context, req resource.UpdateRequest,

// Delete the key
if err := s.client.SSHKeys.DeleteSSHKey(&juju.DeleteSSHKeyInput{
Username: s.client.Username(),
ModelName: modelName,
KeyIdentifier: keyIdentifier,
}); err != nil {
Expand All @@ -231,6 +234,7 @@ func (s *sshKeyResource) Update(ctx context.Context, req resource.UpdateRequest,

// Create a new key
if err := s.client.SSHKeys.CreateSSHKey(&juju.CreateSSHKeyInput{
Username: s.client.Username(),
ModelName: plan.ModelName.ValueString(),
Payload: plan.Payload.ValueString(),
}); err != nil {
Expand Down Expand Up @@ -274,6 +278,7 @@ func (s *sshKeyResource) Delete(ctx context.Context, req resource.DeleteRequest,

// Delete the key
if err := s.client.SSHKeys.DeleteSSHKey(&juju.DeleteSSHKeyInput{
Username: s.client.Username(),
ModelName: modelName,
KeyIdentifier: keyIdentifier,
}); err != nil {
Expand Down

0 comments on commit 575152c

Please sign in to comment.