Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fall back to Rancher-configured CA bundles #3233

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
14 changes: 14 additions & 0 deletions .github/scripts/create-secrets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

dir=${1-'FleetCI-RootCA'}

# Create secret with certs, needed by test git server
kubectl -n fleet-local create secret generic git-server-certs \
--from-file=./"$dir"/helm.crt \
--from-file=./"$dir"/helm.key

# Create cattle-system namespace
kubectl create ns cattle-system

# Create Rancher CA bundle secret
kubectl -n cattle-system create secret generic tls-ca-additional --from-file=ca-additional.pem=./"$dir"/root.crt
1 change: 1 addition & 0 deletions .github/scripts/create-zot-certs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ if [ $? -eq 1 ]; then
[alt_names]
DNS.1 = zot-service.$FLEET_E2E_NS.svc.cluster.local
DNS.2 = chartmuseum-service.$FLEET_E2E_NS.svc.cluster.local
DNS.3 = git-service.$FLEET_E2E_NS.svc.cluster.local
EOF

# sign Zot cert with CA root key
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/e2e-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
FLEET_E2E_NS: fleet-local
run: |
./.github/scripts/create-zot-certs.sh "FleetCI-RootCA"
./.github/scripts/create-secrets.sh 'FleetCI-RootCA'
-
name: E2E Infra Tests
if: ${{ matrix.test_type.name == 'infra-setup' }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/e2e-nightly-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ jobs:
run: |
# Generate cert and key for TLS
./.github/scripts/create-zot-certs.sh "FleetCI-RootCA"
./.github/scripts/create-secrets.sh 'FleetCI-RootCA'
-
name: E2E Tests
if: ${{ matrix.test_type == 'e2e-nosecrets' }}
Expand Down
1 change: 1 addition & 0 deletions dev/setup-k3d
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,6 @@ k3d cluster create "$name" \
-p "$(( 8081 + offs )):8081@server:0" \
-p "$(( 8082 + offs )):8082@server:0" \
-p "$unique_tls_port:443@server:0" \
-p "8043:4343@server:0" \
--k3s-arg '--tls-san=k3d-upstream-server-0@server:0' \
$args
1 change: 1 addition & 0 deletions dev/setup-multi-cluster
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ fi
# needed for gitrepo tests
./dev/import-images-tests-k3d
./dev/create-zot-certs 'FleetCI-RootCA' # for OCI tests
./dev/create-secrets 'FleetCI-RootCA'
./e2e/testenv/infra/infra setup
1 change: 1 addition & 0 deletions dev/setup-single-cluster
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ fi
# needed for gitrepo tests
./dev/import-images-tests-k3d
./dev/create-zot-certs 'FleetCI-RootCA' # for OCI tests
./dev/create-secrets 'FleetCI-RootCA'
./e2e/testenv/infra/infra setup
14 changes: 14 additions & 0 deletions e2e/assets/gitrepo/nginx_deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,23 @@ spec:
labels:
app: git-server
spec:
volumes:
- name: git-certs
secret:
secretName: git-server-certs
items:
- key: helm.crt
path: helm.crt
- key: helm.key
path: helm.key
containers:
- name: git-server
image: nginx-git:test
imagePullPolicy: IfNotPresent
ports:
- containerPort: 4343
- containerPort: 8080
volumeMounts:
- name: git-certs
mountPath: "/etc/ssl/certs"
readOnly: true
4 changes: 4 additions & 0 deletions e2e/assets/gitrepo/nginx_git.conf
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
events {}
http {
server {
error_log stderr info;
listen 80;
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/ssl/certs/helm.crt;
ssl_certificate_key /etc/ssl/certs/helm.key;

# This is where the repositories live on the server
root /srv/git;
Expand Down
7 changes: 6 additions & 1 deletion e2e/assets/gitrepo/nginx_service.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ spec:
selector:
app: git-server
ports:
- protocol: TCP
- name: http
protocol: TCP
port: 8080
targetPort: 80
- name: https
protocol: TCP
port: 4343
targetPort: 443
type: LoadBalancer
183 changes: 181 additions & 2 deletions e2e/single-cluster/gitrepo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import (
)

const (
port = 8080
repoName = "repo"
port = 8080
HTTPSPort = 4343
repoName = "repo"
)

var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup"), func() {
Expand Down Expand Up @@ -369,6 +370,184 @@ var _ = Describe("Monitoring Git repos via HTTP for change", Label("infra-setup"
})
})

var _ = Describe("Monitoring Git repos via HTTPS with a custom CA for change", Label("infra-setup"), func() {
var (
tmpDir string
clonedir string
k kubectl.Command
gh *githelper.Git
clone *git.Repository
repoName string
inClusterRepoURL string
gitrepoName string
r = rand.New(rand.NewSource(GinkgoRandomSeed()))
targetNamespace string
)

BeforeEach(func() {
k = env.Kubectl.Namespace(env.Namespace)
})

JustBeforeEach(func() {

// Build git repo URL reachable _within_ the cluster, for the GitRepo
host, err := githelper.BuildGitHostname(env.Namespace)
Expect(err).ToNot(HaveOccurred())

addr, err := githelper.GetExternalRepoAddr(env, HTTPSPort, repoName)
Expect(err).ToNot(HaveOccurred())
addr = strings.Replace(addr, "http://", "https://", 1)

gh = githelper.NewHTTP(addr)

inClusterRepoURL = gh.GetInClusterURL(host, HTTPSPort, repoName)

tmpDir, _ = os.MkdirTemp("", "fleet-")
clonedir = path.Join(tmpDir, repoName)

gitrepoName = testenv.RandomFilename("gitjob-test", r)
})

AfterEach(func() {
_ = os.RemoveAll(tmpDir)

_, err := k.Delete("gitrepo", gitrepoName)
Expect(err).ToNot(HaveOccurred())

// Check that the bundle deployment resource has been deleted
Eventually(func(g Gomega) {
out, _ := k.Get(
"bundledeployments",
"-A",
"-l",
fmt.Sprintf("fleet.cattle.io/repo-name=%s", gitrepoName),
)
g.Expect(out).To(ContainSubstring("No resources found"))
}).Should(Succeed())

out, err := k.Namespace("cattle-fleet-system").Logs(
"-l",
"app=fleet-controller",
"-c",
"fleet-controller",
)
Expect(err).ToNot(HaveOccurred())

// Errors about resources other than bundles or bundle deployments not being found at deletion time
// should be ignored, as they may result from other test suites.
Expect(out).ToNot(MatchRegexp(
`ERROR.*Reconciler error.*Bundle(Deployment)?.fleet.cattle.io \\".*\\" not found`,
))

_, err = k.Delete("ns", targetNamespace, "--wait=false")
Expect(err).ToNot(HaveOccurred())
})

When("updating a git repository monitored via polling", func() {
BeforeEach(func() {
repoName = "repo"
targetNamespace = testenv.NewNamespaceName("target", r)
})

JustBeforeEach(func() {
err := testenv.ApplyTemplate(k, testenv.AssetPath("gitrepo/gitrepo.yaml"), struct {
Name string
Repo string
Branch string
PollingInterval string
TargetNamespace string
}{
gitrepoName,
inClusterRepoURL,
gh.Branch,
"15s", // default
targetNamespace, // to avoid conflicts with other tests
})
Expect(err).ToNot(HaveOccurred())

clone, err = gh.Create(clonedir, testenv.AssetPath("gitrepo/sleeper-chart"), "examples")
Expect(err).ToNot(HaveOccurred())
})

It("updates the deployment", func() {
By("checking the pod exists")
Eventually(func() string {
out, _ := k.Namespace(targetNamespace).Get("pods")
return out
}).Should(ContainSubstring("sleeper-"))

By("updating the git repository")
replace(path.Join(clonedir, "examples", "Chart.yaml"), "0.1.0", "0.2.0")
replace(path.Join(clonedir, "examples", "templates", "deployment.yaml"), "name: sleeper", "name: newsleep")

commit, err := gh.Update(clone)
Expect(err).ToNot(HaveOccurred())

By("updating the gitrepo's status")
expectedStatus := fleet.GitRepoStatus{
Commit: commit,
GitJobStatus: "Current",
StatusBase: fleet.StatusBase{
ReadyClusters: 1,
DesiredReadyClusters: 1,
Summary: fleet.BundleSummary{
NotReady: 0,
WaitApplied: 0,
ErrApplied: 0,
OutOfSync: 0,
Modified: 0,
Ready: 1,
Pending: 0,
DesiredReady: 1,
NonReadyResources: []fleet.NonReadyResource(nil),
},
Display: fleet.StatusDisplay{
ReadyBundleDeployments: "1/1",
},
Conditions: []genericcondition.GenericCondition{
{
Type: "Ready",
Status: "True",
},
{
Type: "Accepted",
Status: "True",
},
{
Type: "Reconciling",
Status: "False",
},
{
Type: "Stalled",
Status: "False",
},
},
ResourceCounts: fleet.ResourceCounts{
Ready: 1,
DesiredReady: 1,
WaitApplied: 0,
Modified: 0,
Orphaned: 0,
Missing: 0,
Unknown: 0,
NotReady: 0,
},
},
}
Eventually(func(g Gomega) {
status := getGitRepoStatus(g, k, gitrepoName)
g.Expect(status).To(matchGitRepoStatus(expectedStatus))
}).Should(Succeed())

By("checking the deployment's new name")
Eventually(func() string {
out, _ := k.Namespace(targetNamespace).Get("deployments")
return out
}).Should(ContainSubstring("newsleep"))
})
})
})

// replace replaces string s with r in the file located at path. That file must exist and be writable.
func replace(path string, s string, r string) {
b, err := os.ReadFile(path)
Expand Down
37 changes: 35 additions & 2 deletions e2e/single-cluster/helm_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import (
. "github.com/onsi/gomega"
)

var _ = Describe("Single Cluster Examples", Label("infra-setup"), func() {
var _ = Describe("GitRepo using Helm chart with auth", Label("infra-setup"), func() {
var (
gitRepoPath string
tmpdir string
k kubectl.Command
gh *githelper.Git
targetNamespace string
helmSecretName string
)

JustBeforeEach(func() {
Expand All @@ -37,7 +38,7 @@ var _ = Describe("Single Cluster Examples", Label("infra-setup"), func() {
}{
inClusterRepoURL,
gitRepoPath,
"helm-secret",
helmSecretName,
})
Expect(err).ToNot(HaveOccurred())

Expand All @@ -49,6 +50,7 @@ var _ = Describe("Single Cluster Examples", Label("infra-setup"), func() {
Context("containing a private OCI-based helm chart", Label("oci-registry"), func() {
BeforeEach(func() {
gitRepoPath = "oci-with-auth"
helmSecretName = "helm-secret"
targetNamespace = fmt.Sprintf("fleet-helm-%s", gitRepoPath)
k = env.Kubectl.Namespace(env.Namespace)

Expand All @@ -62,9 +64,38 @@ var _ = Describe("Single Cluster Examples", Label("infra-setup"), func() {
}).Should(ContainSubstring("sleeper-"))
})
})
Context("containing a private HTTP-based helm chart with repo path and no configured Helm secret name", Label("helm-registry"), func() {
BeforeEach(func() {
gitRepoPath = "http-with-auth-repo-path"
helmSecretName = "helm-secret-no-ca"
targetNamespace = fmt.Sprintf("fleet-helm-%s", gitRepoPath)
k = env.Kubectl.Namespace(env.Namespace)

// No CA bundle in this secret
out, err := k.Create(
"secret", "generic", helmSecretName,
"--from-literal=username="+os.Getenv("CI_OCI_USERNAME"),
"--from-literal=password="+os.Getenv("CI_OCI_PASSWORD"),
)
Expect(err).ToNot(HaveOccurred(), out)
tmpdir, gh = setupGitRepo(gitRepoPath, repoName, port)

DeferCleanup(func() {
_, _ = k.Delete("secret", helmSecretName)
})
})

It("deploys the helm chart", func() {
Eventually(func() string {
out, _ := k.Namespace(targetNamespace).Get("pods", "--field-selector=status.phase==Running")
return out
}).Should(ContainSubstring("sleeper-"))
})
})
Context("containing a private HTTP-based helm chart with repo path", Label("helm-registry"), func() {
BeforeEach(func() {
gitRepoPath = "http-with-auth-repo-path"
helmSecretName = "helm-secret"
targetNamespace = fmt.Sprintf("fleet-helm-%s", gitRepoPath)
k = env.Kubectl.Namespace(env.Namespace)

Expand All @@ -81,6 +112,7 @@ var _ = Describe("Single Cluster Examples", Label("infra-setup"), func() {
Context("containing a private HTTP-based helm chart with chart path", Label("helm-registry"), func() {
BeforeEach(func() {
gitRepoPath = "http-with-auth-chart-path"
helmSecretName = "helm-secret"
targetNamespace = fmt.Sprintf("fleet-helm-%s", gitRepoPath)
k = env.Kubectl.Namespace(env.Namespace)

Expand All @@ -106,6 +138,7 @@ var _ = Describe("Single Cluster Examples", Label("infra-setup"), func() {

// setupGitRepo creates a local clone with data from repoPath and pushes it to that same path on the git server,
// within a common repository named `repo`.
// nolint: unparam // repo and port are always fed with the same value - for now.
func setupGitRepo(repoPath, repo string, port int) (tmpdir string, gh *githelper.Git) {
addr, err := githelper.GetExternalRepoAddr(env, port, repo)
Expect(err).ToNot(HaveOccurred())
Expand Down
Loading
Loading