mirror of https://github.com/status-im/consul.git
agent/connect: Authorize for CertURI
This commit is contained in:
parent
70d1d5bf06
commit
3ef0b93159
|
@ -5,6 +5,8 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CertURI represents a Connect-valid URI value for a TLS certificate.
|
// CertURI represents a Connect-valid URI value for a TLS certificate.
|
||||||
|
@ -15,6 +17,14 @@ import (
|
||||||
// However, we anticipate that we may accept URIs that are also not SPIFFE
|
// However, we anticipate that we may accept URIs that are also not SPIFFE
|
||||||
// compliant and therefore the interface is named as such.
|
// compliant and therefore the interface is named as such.
|
||||||
type CertURI interface {
|
type CertURI interface {
|
||||||
|
// Authorize tests the authorization for this URI as a client
|
||||||
|
// for the given intention. The return value `auth` is only valid if
|
||||||
|
// the second value `match` is true. If the second value `match` is
|
||||||
|
// false, then the intention doesn't match this client and any
|
||||||
|
// result should be ignored.
|
||||||
|
Authorize(*structs.Intention) (auth bool, match bool)
|
||||||
|
|
||||||
|
// URI is the valid URI value used in the cert.
|
||||||
URI() *url.URL
|
URI() *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,36 +89,3 @@ func ParseCertURI(input *url.URL) (CertURI, error) {
|
||||||
|
|
||||||
return nil, fmt.Errorf("SPIFFE ID is not in the expected format")
|
return nil, fmt.Errorf("SPIFFE ID is not in the expected format")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SpiffeIDService is the structure to represent the SPIFFE ID for a service.
|
|
||||||
type SpiffeIDService struct {
|
|
||||||
Host string
|
|
||||||
Namespace string
|
|
||||||
Datacenter string
|
|
||||||
Service string
|
|
||||||
}
|
|
||||||
|
|
||||||
// URI returns the *url.URL for this SPIFFE ID.
|
|
||||||
func (id *SpiffeIDService) URI() *url.URL {
|
|
||||||
var result url.URL
|
|
||||||
result.Scheme = "spiffe"
|
|
||||||
result.Host = id.Host
|
|
||||||
result.Path = fmt.Sprintf("/ns/%s/dc/%s/svc/%s",
|
|
||||||
id.Namespace, id.Datacenter, id.Service)
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// SpiffeIDSigning is the structure to represent the SPIFFE ID for a
|
|
||||||
// signing certificate (not a leaf service).
|
|
||||||
type SpiffeIDSigning struct {
|
|
||||||
ClusterID string // Unique cluster ID
|
|
||||||
Domain string // The domain, usually "consul"
|
|
||||||
}
|
|
||||||
|
|
||||||
// URI returns the *url.URL for this SPIFFE ID.
|
|
||||||
func (id *SpiffeIDSigning) URI() *url.URL {
|
|
||||||
var result url.URL
|
|
||||||
result.Scheme = "spiffe"
|
|
||||||
result.Host = fmt.Sprintf("%s.%s", id.ClusterID, id.Domain)
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package connect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SpiffeIDService is the structure to represent the SPIFFE ID for a service.
|
||||||
|
type SpiffeIDService struct {
|
||||||
|
Host string
|
||||||
|
Namespace string
|
||||||
|
Datacenter string
|
||||||
|
Service string
|
||||||
|
}
|
||||||
|
|
||||||
|
// URI returns the *url.URL for this SPIFFE ID.
|
||||||
|
func (id *SpiffeIDService) URI() *url.URL {
|
||||||
|
var result url.URL
|
||||||
|
result.Scheme = "spiffe"
|
||||||
|
result.Host = id.Host
|
||||||
|
result.Path = fmt.Sprintf("/ns/%s/dc/%s/svc/%s",
|
||||||
|
id.Namespace, id.Datacenter, id.Service)
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertURI impl.
|
||||||
|
func (id *SpiffeIDService) Authorize(ixn *structs.Intention) (bool, bool) {
|
||||||
|
if ixn.SourceNS != structs.IntentionWildcard && ixn.SourceNS != id.Namespace {
|
||||||
|
// Non-matching namespace
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ixn.SourceName != structs.IntentionWildcard && ixn.SourceName != id.Service {
|
||||||
|
// Non-matching name
|
||||||
|
return false, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match, return allow value
|
||||||
|
return ixn.Action == structs.IntentionActionAllow, true
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package connect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSpiffeIDServiceAuthorize(t *testing.T) {
|
||||||
|
ns := structs.IntentionDefaultNamespace
|
||||||
|
serviceWeb := &SpiffeIDService{
|
||||||
|
Host: "1234.consul",
|
||||||
|
Namespace: structs.IntentionDefaultNamespace,
|
||||||
|
Datacenter: "dc01",
|
||||||
|
Service: "web",
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
URI *SpiffeIDService
|
||||||
|
Ixn *structs.Intention
|
||||||
|
Auth bool
|
||||||
|
Match bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"exact source, not matching namespace",
|
||||||
|
serviceWeb,
|
||||||
|
&structs.Intention{
|
||||||
|
SourceNS: "different",
|
||||||
|
SourceName: "db",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"exact source, not matching name",
|
||||||
|
serviceWeb,
|
||||||
|
&structs.Intention{
|
||||||
|
SourceNS: ns,
|
||||||
|
SourceName: "db",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"exact source, allow",
|
||||||
|
serviceWeb,
|
||||||
|
&structs.Intention{
|
||||||
|
SourceNS: serviceWeb.Namespace,
|
||||||
|
SourceName: serviceWeb.Service,
|
||||||
|
Action: structs.IntentionActionAllow,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"exact source, deny",
|
||||||
|
serviceWeb,
|
||||||
|
&structs.Intention{
|
||||||
|
SourceNS: serviceWeb.Namespace,
|
||||||
|
SourceName: serviceWeb.Service,
|
||||||
|
Action: structs.IntentionActionDeny,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"exact namespace, wildcard service, deny",
|
||||||
|
serviceWeb,
|
||||||
|
&structs.Intention{
|
||||||
|
SourceNS: serviceWeb.Namespace,
|
||||||
|
SourceName: structs.IntentionWildcard,
|
||||||
|
Action: structs.IntentionActionDeny,
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"exact namespace, wildcard service, allow",
|
||||||
|
serviceWeb,
|
||||||
|
&structs.Intention{
|
||||||
|
SourceNS: serviceWeb.Namespace,
|
||||||
|
SourceName: structs.IntentionWildcard,
|
||||||
|
Action: structs.IntentionActionAllow,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range cases {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
auth, match := tc.URI.Authorize(tc.Ixn)
|
||||||
|
assert.Equal(t, tc.Auth, auth)
|
||||||
|
assert.Equal(t, tc.Match, match)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package connect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SpiffeIDSigning is the structure to represent the SPIFFE ID for a
|
||||||
|
// signing certificate (not a leaf service).
|
||||||
|
type SpiffeIDSigning struct {
|
||||||
|
ClusterID string // Unique cluster ID
|
||||||
|
Domain string // The domain, usually "consul"
|
||||||
|
}
|
||||||
|
|
||||||
|
// URI returns the *url.URL for this SPIFFE ID.
|
||||||
|
func (id *SpiffeIDSigning) URI() *url.URL {
|
||||||
|
var result url.URL
|
||||||
|
result.Scheme = "spiffe"
|
||||||
|
result.Host = fmt.Sprintf("%s.%s", id.ClusterID, id.Domain)
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertURI impl.
|
||||||
|
func (id *SpiffeIDSigning) Authorize(ixn *structs.Intention) (bool, bool) {
|
||||||
|
// Never authorize as a client.
|
||||||
|
return false, true
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package connect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Signing ID should never authorize
|
||||||
|
func TestSpiffeIDSigningAuthorize(t *testing.T) {
|
||||||
|
var id SpiffeIDSigning
|
||||||
|
auth, ok := id.Authorize(nil)
|
||||||
|
assert.False(t, auth)
|
||||||
|
assert.True(t, ok)
|
||||||
|
}
|
Loading…
Reference in New Issue