Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit ccc1be2

Browse files
Fix and improve acorn login validation check (#922)
- Add --skip-checks as an escape hatch for trying to authenticate during `acorn login - Rename `acorn install --checks` to `acorn install --skip-checks` for symmetry - Fix the check itself so that authing against quay.io works (by removing the pull/push scopes from the authentication call) - Move the check server side Signed-off-by: Joshua Silverio <[email protected]> Signed-off-by: Craig Jellick <[email protected]> Co-authored-by: Craig Jellick <[email protected]>
1 parent b316d34 commit ccc1be2

File tree

14 files changed

+92
-66
lines changed

14 files changed

+92
-66
lines changed

docs/docs/100-reference/01-command-line/acorn_credential_login.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ acorn login ghcr.io
2222
-h, --help help for login
2323
-p, --password string Password
2424
--password-stdin Take the password from stdin
25+
--skip-checks Bypass login validation checks
2526
-u, --username string Username
2627
```
2728

docs/docs/100-reference/01-command-line/acorn_install.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ acorn install
2323
--acorn-dns-endpoint string The URL to access the Acorn DNS service
2424
--api-server-replicas int acorn-api deployment replica count
2525
--auto-upgrade-interval string For apps configured with automatic upgrades enabled, the interval at which to check for new versions. Upgrade intervals configured at the application level cannot be smaller than this. (default '5m' - 5 minutes)
26-
--checks Disable preflight checks with --checks=false
2726
--cluster-domain strings The externally addressable cluster domain (default .on-acorn.io)
2827
--controller-replicas int acorn-controller deployment replica count
2928
--default-publish-mode string If no publish mode is set default to this value (default user)
@@ -37,6 +36,7 @@ acorn install
3736
-o, --output string Output manifests instead of applying them (json, yaml)
3837
--pod-security-enforce-profile string The name of the PodSecurity profile to set (default baseline)
3938
--set-pod-security-enforce-profile Set the PodSecurity profile on created namespaces (default true)
39+
--skip-checks Bypass installation checks
4040
```
4141

4242
### Options inherited from parent commands

docs/docs/100-reference/01-command-line/acorn_login.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ acorn login ghcr.io
2222
-h, --help help for login
2323
-p, --password string Password
2424
--password-stdin Take the password from stdin
25+
--skip-checks Bypass login validation checks
2526
-u, --username string Username
2627
```
2728

integration/client/credentials/credentials_test.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestCredentialCreate(t *testing.T) {
2828
t.Fatal(err)
2929
}
3030

31-
cred, err := c.CredentialCreate(ctx, reg, "user", "pass")
31+
cred, err := c.CredentialCreate(ctx, reg, "user", "pass", false)
3232
if err != nil {
3333
t.Fatal(err)
3434
}
@@ -38,7 +38,7 @@ func TestCredentialCreate(t *testing.T) {
3838
assert.Equal(t, "user", cred.Username)
3939
assert.Nil(t, cred.Password)
4040

41-
cred1, err := c.CredentialCreate(ctx, reg1, "user2", "pass2")
41+
cred1, err := c.CredentialCreate(ctx, reg1, "user2", "pass2", false)
4242
if err != nil {
4343
t.Fatal(err)
4444
}
@@ -74,12 +74,12 @@ func TestCredentialList(t *testing.T) {
7474
t.Fatal(err)
7575
}
7676

77-
cred1, err := c.CredentialCreate(ctx, reg, "user", "pass")
77+
cred1, err := c.CredentialCreate(ctx, reg, "user", "pass", false)
7878
if err != nil {
7979
t.Fatal(err)
8080
}
8181

82-
cred2, err := c.CredentialCreate(ctx, reg1, "user2", "pass2")
82+
cred2, err := c.CredentialCreate(ctx, reg1, "user2", "pass2", false)
8383
if err != nil {
8484
t.Fatal(err)
8585
}
@@ -115,12 +115,12 @@ func TestCredentialGet(t *testing.T) {
115115
t.Fatal(err)
116116
}
117117

118-
_, err = c.CredentialCreate(ctx, reg, "user", "pass")
118+
_, err = c.CredentialCreate(ctx, reg, "user", "pass", false)
119119
if err != nil {
120120
t.Fatal(err)
121121
}
122122

123-
cred1, err := c.CredentialCreate(ctx, reg1, "user2", "pass2")
123+
cred1, err := c.CredentialCreate(ctx, reg1, "user2", "pass2", false)
124124
if err != nil {
125125
t.Fatal(err)
126126
}
@@ -151,17 +151,17 @@ func TestCredentialUpdate(t *testing.T) {
151151
t.Fatal(err)
152152
}
153153

154-
_, err = c.CredentialCreate(ctx, reg, "user", "pass")
154+
_, err = c.CredentialCreate(ctx, reg, "user", "pass", false)
155155
if err != nil {
156156
t.Fatal(err)
157157
}
158158

159-
_, err = c.CredentialCreate(ctx, reg1, "user2", "pass2")
159+
_, err = c.CredentialCreate(ctx, reg1, "user2", "pass2", false)
160160
if err != nil {
161161
t.Fatal(err)
162162
}
163163

164-
cred1New, err := c.CredentialUpdate(ctx, reg1, "user3", "pass3")
164+
cred1New, err := c.CredentialUpdate(ctx, reg1, "user3", "pass3", false)
165165
if err != nil {
166166
t.Fatal(err)
167167
}
@@ -194,12 +194,12 @@ func TestCredentialDelete(t *testing.T) {
194194
t.Fatal(err)
195195
}
196196

197-
_, err = c.CredentialCreate(ctx, reg, "user", "pass")
197+
_, err = c.CredentialCreate(ctx, reg, "user", "pass", false)
198198
if err != nil {
199199
t.Fatal(err)
200200
}
201201

202-
_, err = c.CredentialCreate(ctx, reg1, "user2", "pass2")
202+
_, err = c.CredentialCreate(ctx, reg1, "user2", "pass2", false)
203203
if err != nil {
204204
t.Fatal(err)
205205
}

pkg/apis/api.acorn.io/v1/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ type Credential struct {
242242
ServerAddress string `json:"serverAddress,omitempty"`
243243
Username string `json:"username,omitempty"`
244244
Password *string `json:"password,omitempty"`
245+
SkipChecks bool `json:"skipChecks,omitempty"`
245246
}
246247

247248
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

pkg/cli/credential_login.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ acorn login ghcr.io`,
3030
}
3131

3232
type CredentialLogin struct {
33+
SkipChecks bool `usage:"Bypass login validation checks"`
3334
PasswordStdin bool `usage:"Take the password from stdin"`
3435
Password string `usage:"Password" short:"p"`
3536
Username string `usage:"Username" short:"u"`
@@ -71,7 +72,7 @@ func (a *CredentialLogin) Run(cmd *cobra.Command, args []string) error {
7172

7273
existing, err := client.CredentialGet(cmd.Context(), args[0])
7374
if apierror.IsNotFound(err) {
74-
cred, err := client.CredentialCreate(cmd.Context(), args[0], a.Username, a.Password)
75+
cred, err := client.CredentialCreate(cmd.Context(), args[0], a.Username, a.Password, a.SkipChecks)
7576
if err != nil {
7677
return err
7778
}
@@ -82,7 +83,7 @@ func (a *CredentialLogin) Run(cmd *cobra.Command, args []string) error {
8283

8384
existing.Username = a.Username
8485
existing.Password = &a.Password
85-
cred, err := client.CredentialUpdate(cmd.Context(), args[0], a.Username, a.Password)
86+
cred, err := client.CredentialUpdate(cmd.Context(), args[0], a.Username, a.Password, a.SkipChecks)
8687
if err != nil {
8788
return err
8889
}

pkg/cli/install.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ acorn install`,
2020
}
2121

2222
type Install struct {
23-
Checks *bool `usage:"Disable preflight checks with --checks=false"`
23+
SkipChecks bool `usage:"Bypass installation checks"`
2424

2525
Image string `usage:"Override the default image used for the deployment"`
2626
Output string `usage:"Output manifests instead of applying them (json, yaml)" short:"o"`
@@ -38,7 +38,7 @@ func (i *Install) Run(cmd *cobra.Command, args []string) error {
3838
}
3939

4040
return install.Install(cmd.Context(), image, &install.Options{
41-
Checks: i.Checks,
41+
SkipChecks: i.SkipChecks,
4242
OutputFormat: i.Output,
4343
Config: i.Config,
4444
APIServerReplicas: i.APIServerReplicas,

pkg/client/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,10 @@ type Client interface {
194194
AppLog(ctx context.Context, name string, opts *LogOptions) (<-chan apiv1.LogMessage, error)
195195
AppConfirmUpgrade(ctx context.Context, name string) error
196196

197-
CredentialCreate(ctx context.Context, serverAddress, username, password string) (*apiv1.Credential, error)
197+
CredentialCreate(ctx context.Context, serverAddress, username, password string, skipChecks bool) (*apiv1.Credential, error)
198198
CredentialList(ctx context.Context) ([]apiv1.Credential, error)
199199
CredentialGet(ctx context.Context, serverAddress string) (*apiv1.Credential, error)
200-
CredentialUpdate(ctx context.Context, serverAddress, username, password string) (*apiv1.Credential, error)
200+
CredentialUpdate(ctx context.Context, serverAddress, username, password string, skipChecks bool) (*apiv1.Credential, error)
201201
CredentialDelete(ctx context.Context, serverAddress string) (*apiv1.Credential, error)
202202

203203
SecretCreate(ctx context.Context, name, secretType string, data map[string][]byte) (*apiv1.Secret, error)

pkg/client/credentials.go

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,15 @@ package client
22

33
import (
44
"context"
5-
"net/http"
65
"sort"
76

87
apiv1 "github.com/acorn-io/acorn/pkg/apis/api.acorn.io/v1"
9-
"github.com/google/go-containerregistry/pkg/authn"
10-
"github.com/google/go-containerregistry/pkg/name"
11-
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
128
apierrors "k8s.io/apimachinery/pkg/api/errors"
139
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1410
kclient "sigs.k8s.io/controller-runtime/pkg/client"
1511
)
1612

17-
func (c *client) CredentialCreate(ctx context.Context, serverAddress, username, password string) (*apiv1.Credential, error) {
18-
if err := credentialValidate(ctx, username, password, serverAddress); err != nil {
19-
return nil, err
20-
}
21-
13+
func (c *client) CredentialCreate(ctx context.Context, serverAddress, username, password string, skipChecks bool) (*apiv1.Credential, error) {
2214
credential := &apiv1.Credential{
2315
ObjectMeta: metav1.ObjectMeta{
2416
Name: serverAddress,
@@ -27,6 +19,7 @@ func (c *client) CredentialCreate(ctx context.Context, serverAddress, username,
2719
ServerAddress: serverAddress,
2820
Username: username,
2921
Password: &password,
22+
SkipChecks: skipChecks,
3023
}
3124
return credential, c.Client.Create(ctx, credential)
3225
}
@@ -39,11 +32,7 @@ func (c *client) CredentialGet(ctx context.Context, serverAddress string) (*apiv
3932
}, credential)
4033
}
4134

42-
func (c *client) CredentialUpdate(ctx context.Context, serverAddress, username, password string) (*apiv1.Credential, error) {
43-
if err := credentialValidate(ctx, username, password, serverAddress); err != nil {
44-
return nil, err
45-
}
46-
35+
func (c *client) CredentialUpdate(ctx context.Context, serverAddress, username, password string, skipChecks bool) (*apiv1.Credential, error) {
4736
credential := &apiv1.Credential{}
4837
err := c.Client.Get(ctx, kclient.ObjectKey{
4938
Name: serverAddress,
@@ -55,6 +44,7 @@ func (c *client) CredentialUpdate(ctx context.Context, serverAddress, username,
5544

5645
credential.Username = username
5746
credential.Password = &password
47+
credential.SkipChecks = skipChecks
5848
return credential, c.Client.Update(ctx, credential)
5949
}
6050

@@ -96,23 +86,3 @@ func (c *client) CredentialDelete(ctx context.Context, serverAddress string) (*a
9686
}
9787
return credential, err
9888
}
99-
100-
// credentialValidate takes a username, password and serverAddress string to validate
101-
// whether their combination is valid and will succeed login for pushes/pulls.
102-
func credentialValidate(ctx context.Context, username, password, serverAddress string) error {
103-
// Build a registry struct for the host
104-
reg, err := name.NewRegistry(serverAddress)
105-
if err != nil {
106-
return err
107-
}
108-
109-
// Build a new transport for the registry which validates authentication
110-
scopes := []string{transport.PullScope, transport.PushScope}
111-
auth := &authn.Basic{Username: username, Password: password}
112-
_, err = transport.NewWithContext(ctx, reg, auth, http.DefaultTransport, scopes)
113-
if err != nil {
114-
return err
115-
}
116-
117-
return nil
118-
}

pkg/client/ignore.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,9 @@ func (c IgnoreUninstalled) BuilderRegistryDialer(ctx context.Context) (func(ctx
204204
})
205205
}
206206

207-
func (c IgnoreUninstalled) CredentialCreate(ctx context.Context, serverAddress, username, password string) (*apiv1.Credential, error) {
207+
func (c IgnoreUninstalled) CredentialCreate(ctx context.Context, serverAddress, username, password string, skipChecks bool) (*apiv1.Credential, error) {
208208
return promptInstall(ctx, func() (*apiv1.Credential, error) {
209-
return c.client.CredentialCreate(ctx, serverAddress, username, password)
209+
return c.client.CredentialCreate(ctx, serverAddress, username, password, skipChecks)
210210
})
211211
}
212212

@@ -218,8 +218,8 @@ func (c IgnoreUninstalled) CredentialGet(ctx context.Context, serverAddress stri
218218
return c.client.CredentialGet(ctx, serverAddress)
219219
}
220220

221-
func (c IgnoreUninstalled) CredentialUpdate(ctx context.Context, serverAddress, username, password string) (*apiv1.Credential, error) {
222-
return c.client.CredentialUpdate(ctx, serverAddress, username, password)
221+
func (c IgnoreUninstalled) CredentialUpdate(ctx context.Context, serverAddress, username, password string, skipChecks bool) (*apiv1.Credential, error) {
222+
return c.client.CredentialUpdate(ctx, serverAddress, username, password, skipChecks)
223223
}
224224

225225
func (c IgnoreUninstalled) CredentialDelete(ctx context.Context, serverAddress string) (*apiv1.Credential, error) {

pkg/install/install.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ var (
5656
type Mode string
5757

5858
type Options struct {
59-
Checks *bool
59+
SkipChecks bool
6060
OutputFormat string
6161
APIServerReplicas *int
6262
ControllerReplicas *int
@@ -167,7 +167,7 @@ func Install(ctx context.Context, image string, opts *Options) error {
167167
}
168168

169169
checkOpts := CheckOptions{RuntimeImage: image}
170-
if opts.Checks == nil || *opts.Checks {
170+
if !opts.SkipChecks {
171171
s := opts.Progress.New("Running Pre-install Checks")
172172
checkResults := PreInstallChecks(ctx, checkOpts)
173173
if IsFailed(checkResults) {
@@ -233,16 +233,20 @@ func Install(ctx context.Context, image string, opts *Options) error {
233233
return err
234234
}
235235

236-
s = opts.Progress.New("Running Post-install Checks")
237-
checkResults := PostInstallChecks(ctx, checkOpts)
238-
if IsFailed(checkResults) {
239-
msg := "Post-install checks failed. Use `acorn check` to debug or `acorn install --checks=false` to skip"
240-
for _, result := range checkResults {
241-
if !result.Passed {
242-
msg += fmt.Sprintf("\n%s: %s", result.Name, result.Message)
236+
if !opts.SkipChecks {
237+
s = opts.Progress.New("Running Post-install Checks")
238+
checkResults := PostInstallChecks(ctx, checkOpts)
239+
if IsFailed(checkResults) {
240+
msg := "Post-install checks failed. Use `acorn check` to debug or `acorn install --checks=false` to skip"
241+
for _, result := range checkResults {
242+
if !result.Passed {
243+
msg += fmt.Sprintf("\n%s: %s", result.Name, result.Message)
244+
}
243245
}
246+
s.SuccessWithWarning(msg)
247+
} else {
248+
s.Success()
244249
}
245-
s.SuccessWithWarning(msg)
246250
} else {
247251
s.Success()
248252
}

pkg/openapi/generated/openapi_generated.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/server/registry/credentials/strategy.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/acorn-io/mink/pkg/strategy/translation"
1111
corev1 "k8s.io/api/core/v1"
1212
"k8s.io/apimachinery/pkg/runtime"
13+
"k8s.io/apimachinery/pkg/util/validation/field"
1314
"k8s.io/apiserver/pkg/registry/rest"
1415
kclient "sigs.k8s.io/controller-runtime/pkg/client"
1516
)
@@ -37,3 +38,16 @@ func (s *Strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
3738
cred := obj.(*apiv1.Credential)
3839
cred.ServerAddress = normalizeDockerIO(cred.ServerAddress)
3940
}
41+
func (s *Strategy) Validate(ctx context.Context, obj runtime.Object) (result field.ErrorList) {
42+
params := obj.(*apiv1.Credential)
43+
if !params.SkipChecks {
44+
if err := s.credentialValidate(ctx, params.Username, *params.Password, params.ServerAddress); err != nil {
45+
result = append(result, field.Forbidden(field.NewPath("username/password"), err.Error()))
46+
}
47+
}
48+
return result
49+
}
50+
func (s *Strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) (result field.ErrorList) {
51+
params := obj.(*apiv1.Credential)
52+
return s.Validate(ctx, params)
53+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package credentials
2+
3+
import (
4+
"context"
5+
"github.com/google/go-containerregistry/pkg/authn"
6+
"github.com/google/go-containerregistry/pkg/name"
7+
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
8+
"net/http"
9+
)
10+
11+
// credentialValidate takes a username, password and serverAddress string to validate
12+
// whether their combination is valid and will succeed login for pushes/pulls.
13+
func (s *Strategy) credentialValidate(ctx context.Context, username, password, serverAddress string) error {
14+
// Build a registry struct for the host
15+
reg, err := name.NewRegistry(serverAddress)
16+
if err != nil {
17+
return err
18+
}
19+
20+
// Build a new transport for the registry which validates authentication
21+
auth := &authn.Basic{Username: username, Password: password}
22+
_, err = transport.NewWithContext(ctx, reg, auth, http.DefaultTransport, nil)
23+
if err != nil {
24+
return err
25+
}
26+
27+
return nil
28+
}

0 commit comments

Comments
 (0)