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

Credentialz-5 #3377

Merged
merged 4 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Credentialz-5: Hiba Authentication

## Summary

Test that Credentialz properly configures (hiba) certificate authentication.


## Procedure

* Follow the instructions for setting up a [HIBA CA](https://github.com/google/hiba/blob/main/CA.md)
* Set DUT allowed authentication types to only public key using gnsi.Credentialz
* Create a user `testuser` (with no certificate at this point)
* Set the AuthorizedPrincipalsCommand by setting the tool to `TOOL_HIBA_DEFAULT`

* Perform the following tests and assert the expected result:
* Case 1: Failure
* Authenticate with the `testuser` username and the previously created public key via SSH
* Assert that authentication has failed (because the DUT doesn't have the Hiba host certificate at this point)
* Ensure that access rejects telemetry counter is incremented `/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-rejects`
* Case 2: Success
* Configure the dut with the Hiba host certificate.
* Authenticate with the `testuser` username the previously created public key via SSH
* Assert that authentication has been successful
* Ensure telemetry values for version and created-on match the values set by
RotateHostParameters for
`/oc-sys:system/oc-sys:ssh-server/oc-sys:state:active-host-certificate-version`
and
`/oc-sys:system/oc-sys:ssh-server/oc-sys:state:active-host-certificate-created-on`
* Ensure that access accept telemetry counters are incremented after successful login
`/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:access-accepts`
`/oc-sys:system/oc-sys:ssh-server/oc-sys:state:counters:last-access-accept`


## OpenConfig Path and RPC Coverage

The below yaml defines the OC paths intended to be covered by this test. OC paths used for test setup are not listed here.

```yaml
paths:
## State Paths ##
/system/ssh-server/state/active-host-certificate-version:
/system/ssh-server/state/active-host-certificate-created-on:
/system/ssh-server/state/counters/access-accepts:
/system/ssh-server/state/counters/last-access-accept:
/system/ssh-server/state/counters/access-rejects:

rpcs:
gnsi:
credentialz.v1.Credentialz.RotateHostParameters:
```


## Minimum DUT platform requirement

N/A
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package hibaauthentication

import (
"fmt"
"os"
"testing"
"time"

"github.com/google/go-cmp/cmp"
"github.com/openconfig/featureprofiles/internal/security/credz"
"github.com/openconfig/ondatra/gnmi"

"github.com/openconfig/featureprofiles/internal/deviations"
"github.com/openconfig/featureprofiles/internal/fptest"
cpb "github.com/openconfig/gnsi/credentialz"
"github.com/openconfig/ondatra"
)

const (
username = "testuser"
hostCertificateVersion = "v1.0"
)

var (
hostCertificateCreatedOn = time.Now().Unix()
)

func TestMain(m *testing.M) {
fptest.RunTests(m)
}

func TestCredentialz(t *testing.T) {
dut := ondatra.DUT(t, "dut")
target := credz.GetDutTarget(t, dut)

// Create temporary directory for storing ssh keys/certificates.
dir, err := os.MkdirTemp("", "")
if err != nil {
t.Fatalf("creating temp dir, err: %s", err)
}
defer func(dir string) {
err = os.RemoveAll(dir)
if err != nil {
t.Logf("error removing temp directory, error: %s", err)
}
}(dir)

credz.CreateHibaKeys(t, dir)
credz.SetupUser(t, dut, username)

// Set only public key authentication for our test.
credz.RotateAuthenticationTypes(t, dut, []cpb.AuthenticationType{
cpb.AuthenticationType_AUTHENTICATION_TYPE_PUBKEY,
})

// Setup hiba for authorized principals command.
credz.RotateAuthorizedPrincipalCheck(t, dut, cpb.AuthorizedPrincipalCheckRequest_TOOL_HIBA_DEFAULT)

t.Run("auth should fail hiba host certificate not present", func(t *testing.T) {
var startingRejectCounter uint64
if !deviations.SSHServerCountersUnsupported(dut) {
startingRejectCounter, _ = credz.GetRejectTelemetry(t, dut)
}

// Verify ssh with hiba fails as expected.
_, err := credz.SSHWithCertificate(t, target, username, fmt.Sprintf("%s/users", dir))
if err == nil {
t.Fatalf("Dialing ssh succeeded, but we expected to fail")
}

if !deviations.SSHServerCountersUnsupported(dut) {
endingRejectCounter, _ := credz.GetRejectTelemetry(t, dut)
if endingRejectCounter <= startingRejectCounter {
t.Fatalf("SSH server reject counter did not increment after unsuccessful login. startCounter: %v, endCounter: %v", startingRejectCounter, endingRejectCounter)
}
}
})

t.Run("auth should succeed ssh public key authorized for user with hiba granted certificate", func(t *testing.T) {
// Push host key/certificate to the dut.
credz.RotateAuthenticationArtifacts(t,
dut,
fmt.Sprintf("%s/hosts", dir),
fmt.Sprintf("%s/hosts", dir),
hostCertificateVersion,
uint64(hostCertificateCreatedOn),
)

// Setup trusted user ca on the dut.
credz.RotateTrustedUserCA(t, dut, dir)

var startingAcceptCounter, startingLastAcceptTime uint64
if !deviations.SSHServerCountersUnsupported(dut) {
startingAcceptCounter, startingLastAcceptTime = credz.GetAcceptTelemetry(t, dut)
}

_, err := credz.SSHWithCertificate(t, target, username, fmt.Sprintf("%s/users", dir))
if err != nil {
t.Fatalf("Dialing ssh failed, but we expected to succeed, errror: %s", err)
}

// Verify ssh counters.
if !deviations.SSHServerCountersUnsupported(dut) {
endingAcceptCounter, endingLastAcceptTime := credz.GetAcceptTelemetry(t, dut)
if endingAcceptCounter <= startingAcceptCounter {
t.Fatalf("SSH server accept counter did not increment after successful login. startCounter: %v, endCounter: %v", startingAcceptCounter, endingAcceptCounter)
}
if startingLastAcceptTime == endingLastAcceptTime {
t.Fatalf("SSH server accept last timestamp did not update after successful login. Timestamp: %v", endingLastAcceptTime)
}
}

// Verify host certificate telemetry.
sshServer := gnmi.Get(t, dut, gnmi.OC().System().SshServer().State())
gotHostCertificateVersion := sshServer.GetActiveHostCertificateVersion()
if !cmp.Equal(gotHostCertificateVersion, hostCertificateVersion) {
t.Fatalf(
"Telemetry reports host certificate version is not correct\n\tgot: %s\n\twant: %s",
gotHostCertificateVersion, hostCertificateVersion,
)
}
gotHostCertificateCreatedOn := sshServer.GetActiveHostCertificateCreatedOn()
if !cmp.Equal(time.Unix(0, int64(gotHostCertificateCreatedOn)), time.Unix(hostCertificateCreatedOn, 0)) {
t.Fatalf(
"Telemetry reports host certificate created on is not correct\n\tgot: %d\n\twant: %d",
gotHostCertificateCreatedOn, hostCertificateCreatedOn,
)
}
})

t.Cleanup(func() {
// Cleanup to remove previous policy which only allowed key auth to make sure we don't leave dut in a
// state where we can't reset config for further tests.
credz.RotateAuthenticationTypes(t, dut, []cpb.AuthenticationType{
cpb.AuthenticationType_AUTHENTICATION_TYPE_PASSWORD,
cpb.AuthenticationType_AUTHENTICATION_TYPE_PUBKEY,
cpb.AuthenticationType_AUTHENTICATION_TYPE_KBDINTERACTIVE,
})

// Remove user ca so subsequent fail cases work.
credz.RotateTrustedUserCA(t, dut, "")

// Clear hiba for authorized principals command.
credz.RotateAuthorizedPrincipalCheck(t, dut, cpb.AuthorizedPrincipalCheckRequest_TOOL_UNSPECIFIED)

// Remove host artifacts from the dut.
credz.RotateAuthenticationArtifacts(t, dut, "", "", "", 0)
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# proto-file: github.com/openconfig/featureprofiles/proto/metadata.proto
# proto-message: Metadata

uuid: "4083a01e-9b52-44c0-aa5c-994e78be66fe"
plan_id: "Credentialz-5"
description: "Hiba Authentication"
testbed: TESTBED_DUT
platform_exceptions: {
platform: {
vendor: NOKIA
}
deviations: {
ssh_server_counters_unsupported: true
}
}
5 changes: 5 additions & 0 deletions internal/deviations/deviations.go
Original file line number Diff line number Diff line change
Expand Up @@ -1181,3 +1181,8 @@ func ChassisGetRPCUnsupported(dut *ondatra.DUTDevice) bool {
func PowerDisableEnableLeafRefValidation(dut *ondatra.DUTDevice) bool {
return lookupDUTDeviations(dut).GetPowerDisableEnableLeafRefValidation()
}

// SSHServerCountersUnsupported is to skip checking ssh server counters.
func SSHServerCountersUnsupported(dut *ondatra.DUTDevice) bool {
return lookupDUTDeviations(dut).GetSshServerCountersUnsupported()
}
Loading
Loading