mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-11 22:49:54 +00:00
* add managed updates artifact signature verification * updating signature max size to a more realistic, yet generous size * fail teleport-update bulds when artifact verifier key is missing * forward artifact signing key into Docker buildbox * verify artifact signature over stream instead of pre-computed digest * add insecure-skip-artifact-signature flag for dev builds * renaming insecure signature flag and simplify verifier flow * import separation for linter CI fix * gofmt * simplifying verifyArfifactSig function, table tests * verify artifact signature during install, adding godoc for WithDigest * adding staging CDN fallback * updating isStagingCDN url check by adding helper function to check for raw vs want url equality, pr comments * clarify ECDSA-specific digest verification comment * initialize artifact signature verifier at construction time * embed backup artifact signature public key for managed updates * move teleport-update signature inputs to main.go * removing comment * verify staging signatures by default with explicit fallback * update staging signature verification to trust prod artifacts * fix test expected message error
308 lines
7.2 KiB
Go
308 lines
7.2 KiB
Go
/*
|
|
* Teleport
|
|
* Copyright (C) 2024 Gravitational, Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package agent
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/gravitational/teleport/lib/autoupdate"
|
|
)
|
|
|
|
func TestNewRevisionFromDir(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, tt := range []struct {
|
|
name string
|
|
dir string
|
|
rev Revision
|
|
errMatch string
|
|
}{
|
|
{
|
|
name: "version",
|
|
dir: "1.2.3",
|
|
rev: Revision{
|
|
Version: "1.2.3",
|
|
},
|
|
},
|
|
{
|
|
name: "full",
|
|
dir: "1.2.3_ent_fips",
|
|
rev: Revision{
|
|
Version: "1.2.3",
|
|
Flags: autoupdate.FlagEnterprise | autoupdate.FlagFIPS,
|
|
},
|
|
},
|
|
{
|
|
name: "ent",
|
|
dir: "1.2.3_ent",
|
|
rev: Revision{
|
|
Version: "1.2.3",
|
|
Flags: autoupdate.FlagEnterprise,
|
|
},
|
|
},
|
|
{
|
|
name: "empty",
|
|
errMatch: "missing",
|
|
},
|
|
{
|
|
name: "trailing",
|
|
dir: "1.2.3_",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "more trailing",
|
|
dir: "1.2.3___",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "no version",
|
|
dir: "_fips",
|
|
errMatch: "missing",
|
|
},
|
|
{
|
|
name: "fips no ent",
|
|
dir: "1.2.3_fips",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "unknown start fips",
|
|
dir: "1.2.3_test_fips",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "unknown start ent",
|
|
dir: "1.2.3_test_ent",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "unknown end fips",
|
|
dir: "1.2.3_fips_test",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "unknown end ent",
|
|
dir: "1.2.3_ent_test",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "bad order",
|
|
dir: "1.2.3_fips_ent",
|
|
errMatch: "invalid",
|
|
},
|
|
{
|
|
name: "underscore",
|
|
dir: "_",
|
|
errMatch: "missing",
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
rev, err := NewRevisionFromDir(tt.dir)
|
|
if tt.errMatch != "" {
|
|
require.ErrorContains(t, err, tt.errMatch)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.rev, rev)
|
|
require.Equal(t, tt.dir, rev.Dir())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateConfigSpec(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, tt := range []struct {
|
|
name string
|
|
config UpdateSpec
|
|
override UpdateSpec
|
|
insecureSkipSignatureVerify bool
|
|
insecureChanged bool
|
|
enableStagingSignatureVerify bool
|
|
enableStagingChanged bool
|
|
result UpdateSpec
|
|
errMatch string
|
|
}{
|
|
{
|
|
name: "overrides",
|
|
config: UpdateSpec{
|
|
Proxy: "proxy",
|
|
Path: "/path",
|
|
Group: "group",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
override: UpdateSpec{
|
|
Enabled: true,
|
|
Pinned: true,
|
|
Proxy: "overrideProxy",
|
|
Path: "/overridePath",
|
|
Group: "group2",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
result: UpdateSpec{
|
|
Enabled: true,
|
|
Pinned: true,
|
|
Proxy: "overrideProxy",
|
|
Path: "/overridePath",
|
|
Group: "group2",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
},
|
|
{
|
|
name: "default overrides",
|
|
config: UpdateSpec{
|
|
Proxy: "proxy",
|
|
Path: "/path",
|
|
Group: "group",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
override: UpdateSpec{
|
|
Proxy: "default",
|
|
Path: "default",
|
|
Group: "default",
|
|
BaseURL: "default",
|
|
},
|
|
result: UpdateSpec{
|
|
Proxy: "default",
|
|
Path: "default",
|
|
},
|
|
},
|
|
{
|
|
name: "only overrides",
|
|
override: UpdateSpec{
|
|
Enabled: true,
|
|
Pinned: true,
|
|
Proxy: "overrideProxy",
|
|
Path: "/overridePath",
|
|
Group: "group2",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
result: UpdateSpec{
|
|
Enabled: true,
|
|
Pinned: true,
|
|
Proxy: "overrideProxy",
|
|
Path: "/overridePath",
|
|
Group: "group2",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
},
|
|
{
|
|
name: "no overrides",
|
|
config: UpdateSpec{
|
|
Proxy: "proxy",
|
|
Path: "/path",
|
|
Group: "group",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
result: UpdateSpec{
|
|
Proxy: "proxy",
|
|
Path: "/path",
|
|
Group: "group",
|
|
BaseURL: "https://example.com",
|
|
},
|
|
},
|
|
{
|
|
name: "BaseURL validation fails",
|
|
override: UpdateSpec{
|
|
BaseURL: "http://example.com",
|
|
},
|
|
errMatch: "must use TLS",
|
|
},
|
|
{
|
|
name: "insecure checksum-only mode allowed",
|
|
override: UpdateSpec{
|
|
BaseURL: "https://example.com",
|
|
},
|
|
insecureSkipSignatureVerify: true,
|
|
insecureChanged: true,
|
|
result: UpdateSpec{
|
|
BaseURL: "https://example.com",
|
|
InsecureSkipSignatureVerify: true,
|
|
},
|
|
},
|
|
{
|
|
name: "insecure checksum-only mode allowed with default base URL",
|
|
insecureSkipSignatureVerify: true,
|
|
insecureChanged: true,
|
|
result: UpdateSpec{
|
|
InsecureSkipSignatureVerify: true,
|
|
},
|
|
},
|
|
{
|
|
name: "insecure checksum-only mode can be cleared",
|
|
config: UpdateSpec{
|
|
BaseURL: "https://example.com",
|
|
InsecureSkipSignatureVerify: true,
|
|
},
|
|
insecureChanged: true,
|
|
result: UpdateSpec{
|
|
BaseURL: "https://example.com",
|
|
},
|
|
},
|
|
{
|
|
name: "enable staging signature verification can be enabled",
|
|
override: UpdateSpec{
|
|
BaseURL: "https://cdn.cloud.gravitational.io",
|
|
},
|
|
enableStagingSignatureVerify: true,
|
|
enableStagingChanged: true,
|
|
result: UpdateSpec{
|
|
BaseURL: "https://cdn.cloud.gravitational.io",
|
|
EnableStagingSignatureVerify: true,
|
|
},
|
|
},
|
|
{
|
|
name: "enable staging signature verification can be cleared",
|
|
config: UpdateSpec{
|
|
BaseURL: "https://cdn.cloud.gravitational.io",
|
|
EnableStagingSignatureVerify: true,
|
|
},
|
|
enableStagingChanged: true,
|
|
result: UpdateSpec{
|
|
BaseURL: "https://cdn.cloud.gravitational.io",
|
|
},
|
|
},
|
|
} {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := updateConfigSpec(&tt.config, OverrideConfig{
|
|
UpdateSpec: UpdateSpec{
|
|
Proxy: tt.override.Proxy,
|
|
Path: tt.override.Path,
|
|
Group: tt.override.Group,
|
|
BaseURL: tt.override.BaseURL,
|
|
Enabled: tt.override.Enabled,
|
|
Pinned: tt.override.Pinned,
|
|
SELinuxSSH: tt.override.SELinuxSSH,
|
|
InsecureSkipSignatureVerify: tt.insecureSkipSignatureVerify,
|
|
EnableStagingSignatureVerify: tt.enableStagingSignatureVerify,
|
|
},
|
|
InsecureSkipSignatureVerifyChanged: tt.insecureChanged,
|
|
EnableStagingSignatureVerifyChanged: tt.enableStagingChanged,
|
|
})
|
|
if tt.errMatch != "" {
|
|
require.ErrorContains(t, err, tt.errMatch)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.result, tt.config)
|
|
})
|
|
}
|
|
}
|