Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
8b57b6fe
Commit
8b57b6fe
authored
May 14, 2015
by
Nghia Tran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Support glob wildcards for gcr.io credentials
parent
50b9d628
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
306 additions
and
54 deletions
+306
-54
metadata.go
pkg/credentialprovider/gcp/metadata.go
+3
-1
keyring.go
pkg/credentialprovider/keyring.go
+78
-3
keyring_test.go
pkg/credentialprovider/keyring_test.go
+225
-50
No files found.
pkg/credentialprovider/gcp/metadata.go
View file @
8b57b6fe
...
@@ -37,7 +37,9 @@ const (
...
@@ -37,7 +37,9 @@ const (
storageScopePrefix
=
"https://www.googleapis.com/auth/devstorage"
storageScopePrefix
=
"https://www.googleapis.com/auth/devstorage"
)
)
var
containerRegistryUrls
=
[]
string
{
"container.cloud.google.com"
,
"gcr.io"
}
// For these urls, the parts of the host name can be glob, for example '*.gcr.io" will match
// "foo.gcr.io" and "bar.gcr.io".
var
containerRegistryUrls
=
[]
string
{
"container.cloud.google.com"
,
"gcr.io"
,
"*.gcr.io"
}
var
metadataHeader
=
&
http
.
Header
{
var
metadataHeader
=
&
http
.
Header
{
"Metadata-Flavor"
:
[]
string
{
"Google"
},
"Metadata-Flavor"
:
[]
string
{
"Google"
},
...
...
pkg/credentialprovider/keyring.go
View file @
8b57b6fe
...
@@ -18,7 +18,9 @@ package credentialprovider
...
@@ -18,7 +18,9 @@ package credentialprovider
import
(
import
(
"encoding/json"
"encoding/json"
"net"
"net/url"
"net/url"
"path/filepath"
"sort"
"sort"
"strings"
"strings"
...
@@ -118,6 +120,79 @@ func isDefaultRegistryMatch(image string) bool {
...
@@ -118,6 +120,79 @@ func isDefaultRegistryMatch(image string) bool {
return
!
strings
.
ContainsAny
(
parts
[
0
],
".:"
)
return
!
strings
.
ContainsAny
(
parts
[
0
],
".:"
)
}
}
// url.Parse require a scheme, but ours don't have schemes. Adding a
// scheme to make url.Parse happy, then clear out the resulting scheme.
func
parseSchemelessUrl
(
schemelessUrl
string
)
(
*
url
.
URL
,
error
)
{
parsed
,
err
:=
url
.
Parse
(
"https://"
+
schemelessUrl
)
if
err
!=
nil
{
return
nil
,
err
}
// clear out the resulting scheme
parsed
.
Scheme
=
""
return
parsed
,
nil
}
// split the host name into parts, as well as the port
func
splitUrl
(
url
*
url
.
URL
)
(
parts
[]
string
,
port
string
)
{
host
,
port
,
err
:=
net
.
SplitHostPort
(
url
.
Host
)
if
err
!=
nil
{
// could not parse port
host
,
port
=
url
.
Host
,
""
}
return
strings
.
Split
(
host
,
"."
),
port
}
// overloaded version of urlsMatch, operating on strings instead of URLs.
func
urlsMatchStr
(
glob
string
,
target
string
)
(
bool
,
error
)
{
globUrl
,
err
:=
parseSchemelessUrl
(
glob
)
if
err
!=
nil
{
return
false
,
err
}
targetUrl
,
err
:=
parseSchemelessUrl
(
target
)
if
err
!=
nil
{
return
false
,
err
}
return
urlsMatch
(
globUrl
,
targetUrl
)
}
// check whether the given target url matches the glob url, which may have
// glob wild cards in the host name.
//
// Examples:
// globUrl=*.docker.io, targetUrl=blah.docker.io => match
// globUrl=*.docker.io, targetUrl=not.right.io => no match
//
// Note that we don't support wildcards in ports and paths yet.
func
urlsMatch
(
globUrl
*
url
.
URL
,
targetUrl
*
url
.
URL
)
(
bool
,
error
)
{
globUrlParts
,
globPort
:=
splitUrl
(
globUrl
)
targetUrlParts
,
targetPort
:=
splitUrl
(
targetUrl
)
if
globPort
!=
targetPort
{
// port doesn't match
return
false
,
nil
}
if
len
(
globUrlParts
)
!=
len
(
targetUrlParts
)
{
// host name does not have the same number of parts
return
false
,
nil
}
if
!
strings
.
HasPrefix
(
targetUrl
.
Path
,
globUrl
.
Path
)
{
// the path of the credential must be a prefix
return
false
,
nil
}
for
k
,
globUrlPart
:=
range
globUrlParts
{
targetUrlPart
:=
targetUrlParts
[
k
]
matched
,
err
:=
filepath
.
Match
(
globUrlPart
,
targetUrlPart
)
if
err
!=
nil
{
return
false
,
err
}
if
!
matched
{
// glob mismatch for some part
return
false
,
nil
}
}
// everything matches
return
true
,
nil
}
// Lookup implements the DockerKeyring method for fetching credentials based on image name.
// Lookup implements the DockerKeyring method for fetching credentials based on image name.
// Multiple credentials may be returned if there are multiple potentially valid credentials
// Multiple credentials may be returned if there are multiple potentially valid credentials
// available. This allows for rotation.
// available. This allows for rotation.
...
@@ -125,9 +200,9 @@ func (dk *BasicDockerKeyring) Lookup(image string) ([]docker.AuthConfiguration,
...
@@ -125,9 +200,9 @@ func (dk *BasicDockerKeyring) Lookup(image string) ([]docker.AuthConfiguration,
// range over the index as iterating over a map does not provide a predictable ordering
// range over the index as iterating over a map does not provide a predictable ordering
ret
:=
[]
docker
.
AuthConfiguration
{}
ret
:=
[]
docker
.
AuthConfiguration
{}
for
_
,
k
:=
range
dk
.
index
{
for
_
,
k
:=
range
dk
.
index
{
//
NOTE: prefix is a sufficient check because while scheme is allowed,
//
both k and image are schemeless URLs because even though schemes are allowed
// i
t is stripped as part of 'Add'
// i
n the credential configurations, we remove them in Add.
if
!
strings
.
HasPrefix
(
image
,
k
)
{
if
matched
,
_
:=
urlsMatchStr
(
k
,
image
);
!
matched
{
continue
continue
}
}
...
...
pkg/credentialprovider/keyring_test.go
View file @
8b57b6fe
...
@@ -22,71 +22,246 @@ import (
...
@@ -22,71 +22,246 @@ import (
"testing"
"testing"
)
)
func
TestDockerKeyringFromBytes
(
t
*
testing
.
T
)
{
func
TestUrlsMatch
(
t
*
testing
.
T
)
{
url
:=
"hello.kubernetes.io"
tests
:=
[]
struct
{
email
:=
"foo@bar.baz"
globUrl
string
username
:=
"foo"
targetUrl
string
password
:=
"bar"
matchExpected
bool
auth
:=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
fmt
.
Sprintf
(
"%s:%s"
,
username
,
password
)))
}{
sampleDockerConfig
:=
fmt
.
Sprintf
(
`{
// match when there is no path component
"https://%s": {
{
"email": %q,
globUrl
:
"*.kubernetes.io"
,
"auth": %q
targetUrl
:
"prefix.kubernetes.io"
,
}
matchExpected
:
true
,
}`
,
url
,
email
,
auth
)
},
{
keyring
:=
&
BasicDockerKeyring
{}
globUrl
:
"prefix.*.io"
,
if
cfg
,
err
:=
readDockerConfigFileFromBytes
([]
byte
(
sampleDockerConfig
));
err
!=
nil
{
targetUrl
:
"prefix.kubernetes.io"
,
t
.
Errorf
(
"Error processing json blob %q, %v"
,
sampleDockerConfig
,
err
)
matchExpected
:
true
,
}
else
{
},
keyring
.
Add
(
cfg
)
{
}
globUrl
:
"prefix.kubernetes.*"
,
targetUrl
:
"prefix.kubernetes.io"
,
creds
,
ok
:=
keyring
.
Lookup
(
url
+
"/foo/bar"
)
matchExpected
:
true
,
if
!
ok
{
},
t
.
Errorf
(
"Didn't find expected URL: %s"
,
url
)
{
return
globUrl
:
"*-good.kubernetes.io"
,
targetUrl
:
"prefix-good.kubernetes.io"
,
matchExpected
:
true
,
},
// match with path components
{
globUrl
:
"*.kubernetes.io/blah"
,
targetUrl
:
"prefix.kubernetes.io/blah"
,
matchExpected
:
true
,
},
{
globUrl
:
"prefix.*.io/foo"
,
targetUrl
:
"prefix.kubernetes.io/foo/bar"
,
matchExpected
:
true
,
},
// match with path components and ports
{
globUrl
:
"*.kubernetes.io:1111/blah"
,
targetUrl
:
"prefix.kubernetes.io:1111/blah"
,
matchExpected
:
true
,
},
{
globUrl
:
"prefix.*.io:1111/foo"
,
targetUrl
:
"prefix.kubernetes.io:1111/foo/bar"
,
matchExpected
:
true
,
},
// no match when number of parts mismatch
{
globUrl
:
"*.kubernetes.io"
,
targetUrl
:
"kubernetes.io"
,
matchExpected
:
false
,
},
{
globUrl
:
"*.*.kubernetes.io"
,
targetUrl
:
"prefix.kubernetes.io"
,
matchExpected
:
false
,
},
{
globUrl
:
"*.*.kubernetes.io"
,
targetUrl
:
"kubernetes.io"
,
matchExpected
:
false
,
},
// no match when some parts mismatch
{
globUrl
:
"kubernetes.io"
,
targetUrl
:
"kubernetes.com"
,
matchExpected
:
false
,
},
{
globUrl
:
"k*.io"
,
targetUrl
:
"quay.io"
,
matchExpected
:
false
,
},
// no match when ports mismatch
{
globUrl
:
"*.kubernetes.io:1234/blah"
,
targetUrl
:
"prefix.kubernetes.io:1111/blah"
,
matchExpected
:
false
,
},
{
globUrl
:
"prefix.*.io/foo"
,
targetUrl
:
"prefix.kubernetes.io:1111/foo/bar"
,
matchExpected
:
false
,
},
}
}
if
len
(
creds
)
>
1
{
for
_
,
test
:=
range
tests
{
t
.
Errorf
(
"Got more hits than expected: %s"
,
creds
)
matched
,
_
:=
urlsMatchStr
(
test
.
globUrl
,
test
.
targetUrl
)
if
matched
!=
test
.
matchExpected
{
t
.
Errorf
(
"Expected match result of %s and %s to be %t, but was %t"
,
test
.
globUrl
,
test
.
targetUrl
,
test
.
matchExpected
,
matched
)
}
}
}
val
:=
creds
[
0
]
}
if
username
!=
val
.
Username
{
func
TestDockerKeyringForGlob
(
t
*
testing
.
T
)
{
t
.
Errorf
(
"Unexpected username value, want: %s, got: %s"
,
username
,
val
.
Username
)
tests
:=
[]
struct
{
}
globUrl
string
if
password
!=
val
.
Password
{
targetUrl
string
t
.
Errorf
(
"Unexpected password value, want: %s, got: %s"
,
password
,
val
.
Password
)
}{
{
globUrl
:
"hello.kubernetes.io"
,
targetUrl
:
"hello.kubernetes.io"
,
},
{
globUrl
:
"*.docker.io"
,
targetUrl
:
"prefix.docker.io"
,
},
{
globUrl
:
"prefix.*.io"
,
targetUrl
:
"prefix.docker.io"
,
},
{
globUrl
:
"prefix.docker.*"
,
targetUrl
:
"prefix.docker.io"
,
},
{
globUrl
:
"*.docker.io/path"
,
targetUrl
:
"prefix.docker.io/path"
,
},
{
globUrl
:
"prefix.*.io/path"
,
targetUrl
:
"prefix.docker.io/path/subpath"
,
},
{
globUrl
:
"prefix.docker.*/path"
,
targetUrl
:
"prefix.docker.io/path"
,
},
{
globUrl
:
"*.docker.io:8888"
,
targetUrl
:
"prefix.docker.io:8888"
,
},
{
globUrl
:
"prefix.*.io:8888"
,
targetUrl
:
"prefix.docker.io:8888"
,
},
{
globUrl
:
"prefix.docker.*:8888"
,
targetUrl
:
"prefix.docker.io:8888"
,
},
{
globUrl
:
"*.docker.io/path:1111"
,
targetUrl
:
"prefix.docker.io/path:1111"
,
},
{
globUrl
:
"prefix.*.io/path:1111"
,
targetUrl
:
"prefix.docker.io/path/subpath:1111"
,
},
{
globUrl
:
"prefix.docker.*/path:1111"
,
targetUrl
:
"prefix.docker.io/path:1111"
,
},
}
}
if
email
!=
val
.
Email
{
for
_
,
test
:=
range
tests
{
t
.
Errorf
(
"Unexpected email value, want: %s, got: %s"
,
email
,
val
.
Email
)
email
:=
"foo@bar.baz"
username
:=
"foo"
password
:=
"bar"
auth
:=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
fmt
.
Sprintf
(
"%s:%s"
,
username
,
password
)))
sampleDockerConfig
:=
fmt
.
Sprintf
(
`{
"https://%s": {
"email": %q,
"auth": %q
}
}`
,
test
.
globUrl
,
email
,
auth
)
keyring
:=
&
BasicDockerKeyring
{}
if
cfg
,
err
:=
readDockerConfigFileFromBytes
([]
byte
(
sampleDockerConfig
));
err
!=
nil
{
t
.
Errorf
(
"Error processing json blob %q, %v"
,
sampleDockerConfig
,
err
)
}
else
{
keyring
.
Add
(
cfg
)
}
creds
,
ok
:=
keyring
.
Lookup
(
test
.
targetUrl
+
"/foo/bar"
)
if
!
ok
{
t
.
Errorf
(
"Didn't find expected URL: %s"
,
test
.
targetUrl
)
return
}
val
:=
creds
[
0
]
if
username
!=
val
.
Username
{
t
.
Errorf
(
"Unexpected username value, want: %s, got: %s"
,
username
,
val
.
Username
)
}
if
password
!=
val
.
Password
{
t
.
Errorf
(
"Unexpected password value, want: %s, got: %s"
,
password
,
val
.
Password
)
}
if
email
!=
val
.
Email
{
t
.
Errorf
(
"Unexpected email value, want: %s, got: %s"
,
email
,
val
.
Email
)
}
}
}
}
}
func
TestKeyringMiss
(
t
*
testing
.
T
)
{
func
TestKeyringMiss
(
t
*
testing
.
T
)
{
url
:=
"hello.kubernetes.io"
tests
:=
[]
struct
{
email
:=
"foo@bar.baz"
globUrl
string
username
:=
"foo"
lookupUrl
string
password
:=
"bar"
}{
auth
:=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
fmt
.
Sprintf
(
"%s:%s"
,
username
,
password
)))
{
sampleDockerConfig
:=
fmt
.
Sprintf
(
`{
globUrl
:
"hello.kubernetes.io"
,
lookupUrl
:
"world.mesos.org/foo/bar"
,
},
{
globUrl
:
"*.docker.com"
,
lookupUrl
:
"prefix.docker.io"
,
},
{
globUrl
:
"suffix.*.io"
,
lookupUrl
:
"prefix.docker.io"
,
},
{
globUrl
:
"prefix.docker.c*"
,
lookupUrl
:
"prefix.docker.io"
,
},
}
for
_
,
test
:=
range
tests
{
email
:=
"foo@bar.baz"
username
:=
"foo"
password
:=
"bar"
auth
:=
base64
.
StdEncoding
.
EncodeToString
([]
byte
(
fmt
.
Sprintf
(
"%s:%s"
,
username
,
password
)))
sampleDockerConfig
:=
fmt
.
Sprintf
(
`{
"https://%s": {
"https://%s": {
"email": %q,
"email": %q,
"auth": %q
"auth": %q
}
}
}`
,
u
rl
,
email
,
auth
)
}`
,
test
.
globU
rl
,
email
,
auth
)
keyring
:=
&
BasicDockerKeyring
{}
keyring
:=
&
BasicDockerKeyring
{}
if
cfg
,
err
:=
readDockerConfigFileFromBytes
([]
byte
(
sampleDockerConfig
));
err
!=
nil
{
if
cfg
,
err
:=
readDockerConfigFileFromBytes
([]
byte
(
sampleDockerConfig
));
err
!=
nil
{
t
.
Errorf
(
"Error processing json blob %q, %v"
,
sampleDockerConfig
,
err
)
t
.
Errorf
(
"Error processing json blob %q, %v"
,
sampleDockerConfig
,
err
)
}
else
{
}
else
{
keyring
.
Add
(
cfg
)
keyring
.
Add
(
cfg
)
}
}
val
,
ok
:=
keyring
.
Lookup
(
"world.mesos.org/foo/bar"
)
_
,
ok
:=
keyring
.
Lookup
(
test
.
lookupUrl
+
"/foo/bar"
)
if
ok
{
if
ok
{
t
.
Errorf
(
"Found unexpected credential: %+v"
,
val
)
t
.
Errorf
(
"Expected not to find URL %s, but found"
,
test
.
lookupUrl
)
}
}
}
}
}
func
TestKeyringMissWithDockerHubCredentials
(
t
*
testing
.
T
)
{
func
TestKeyringMissWithDockerHubCredentials
(
t
*
testing
.
T
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment