Skip to content

Commit

Permalink
Support priority handling for cert signing (AthenZ#1671)
Browse files Browse the repository at this point in the history
Signed-off-by: Ofer Levi <[email protected]>
  • Loading branch information
OferLevi85 authored Nov 11, 2021
1 parent a59e895 commit a7c01ee
Show file tree
Hide file tree
Showing 21 changed files with 489 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ default String generateX509Certificate(String provider, String certIssuer, Strin
return generateX509Certificate(csr, keyUsage, expiryTime);
}

/**
* Generate a signed X509 Certificate based on the given request. The
* signer imposes how long the certificate is valid for. The result
* must be the certificate in PEM format.
* @param provider (optional) Athenz provider that validated certificate request
* @param certIssuer (optional) Request to have cert signed by given issuer
* @param csr Certificate request
* @param keyUsage Requested key usage (null for both server and client,
* otherwise specified usage type: server or client)
* @param expiryTime Requested certificate expiration time in minutes.
* CertSigner might override this value with a smaller value.
* @param priority requested priority for processing the request signing service
* @return X509 Certificate in PEM format
*/
default String generateX509Certificate(String provider, String certIssuer, String csr,
String keyUsage, int expiryTime, Priority priority) {
return generateX509Certificate(csr, keyUsage, expiryTime);
}

/**
* Retrieve the CA certificate in PEM format. This will be returned
* along with the x509 certificate back to the client.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
*
* * Copyright The Athenz Authors
* *
* * 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 com.yahoo.athenz.common.server.cert;

public enum Priority {
Unspecified(0),
High(5),
Medium(10),
Low(15);

public final int getPriorityValue() {
return value;
}

private final int value;

Priority(int value) {
this.value = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public void testCertSignerDefaultMethods() {

assertNull(signer.generateX509Certificate("csr", "client", 60));
assertNull(signer.generateX509Certificate("aws", "us-west-2", "csr", "client", 60));
assertNull(signer.generateX509Certificate("aws", "us-west-2", "csr", "client", 60, Priority.Unspecified));
assertNull(signer.getCACertificate());
assertNull(signer.getCACertificate("aws"));
assertEquals(signer.getMaxCertExpiryTimeMins(), 0);
Expand All @@ -53,6 +54,7 @@ public void testCertSigner() {
CertSigner signer = Mockito.mock(CertSigner.class);
Mockito.when(signer.generateX509Certificate("csr", "client", 100)).thenReturn("cert");
Mockito.when(signer.generateX509Certificate("aws", "us-west-2", "csr", "client", 100)).thenReturn("cert1");
Mockito.when(signer.generateX509Certificate("aws", "us-west-2", "csr", "client", 100, Priority.High)).thenReturn("cert2");
Mockito.when(signer.getCACertificate()).thenReturn("ca-cert");
Mockito.when(signer.getCACertificate("aws")).thenReturn("ca-cert1");
Mockito.when(signer.getMaxCertExpiryTimeMins()).thenReturn(60);
Expand All @@ -63,6 +65,7 @@ public void testCertSigner() {
assertNotNull(testSigner);
assertEquals("cert", testSigner.generateX509Certificate("csr", "client", 100));
assertEquals("cert1", testSigner.generateX509Certificate("aws", "us-west-2", "csr", "client", 100));
assertEquals("cert2", testSigner.generateX509Certificate("aws", "us-west-2", "csr", "client", 100, Priority.High));
assertEquals("ca-cert", testSigner.getCACertificate());
assertEquals("ca-cert1", testSigner.getCACertificate("aws"));
assertEquals(60, testSigner.getMaxCertExpiryTimeMins());
Expand Down
85 changes: 66 additions & 19 deletions provider/aws/sia-ec2/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/AthenZ/athenz/libs/go/sia/logutil"
"github.com/AthenZ/athenz/libs/go/sia/util"
"github.com/AthenZ/athenz/provider/aws/sia-ec2/options"
"github.com/ardielle/ardielle-go/rdl"
"io"
"io/ioutil"
"log"
Expand All @@ -47,6 +48,38 @@ type Identity struct {
Ip string
}

func GetPrevRoleCertDates(role options.Role, opts *options.Options) (*rdl.Timestamp, *rdl.Timestamp, error) {
certPrefix := role.Name
if role.Filename != "" {
certPrefix = strings.TrimSuffix(role.Filename, ".cert.pem")
}
keyPrefix := fmt.Sprintf("%s.%s", opts.Domain, role.Service)
if opts.GenerateRoleKey == true {
keyPrefix = role.Name
if role.Filename != "" {
keyPrefix = strings.TrimSuffix(role.Filename, ".cert.pem")
}
}

certFile, _ := getCertKeyFileName(role.Filename, opts.KeyDir, opts.CertDir, keyPrefix, certPrefix)

prevRolCert, err := readCertificate(certFile)
if err != nil {
return nil, nil, err
}

notBefore := &rdl.Timestamp{
Time: prevRolCert.NotBefore,
}

notAfter := &rdl.Timestamp{
Time: prevRolCert.NotAfter,
}

log.Printf("Existing role cert %s, not before: %s, not after: %s", certFile, notBefore.String(), notAfter.String())
return notBefore, notAfter, nil
}

func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Options, sysLogger io.Writer) bool {
client, err := util.ZtsClient(ztsUrl, opts.ZTSServerName, svcKeyFile, svcCertFile, opts.ZTSCACertFile, sysLogger)
if err != nil {
Expand Down Expand Up @@ -93,6 +126,24 @@ func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Op
continue
}
roleRequest.Csr = csr

optsRole := options.Role{
Name: roleName,
Service: opts.Services[0].Name,
Filename: role.Filename,
User: "",
Uid: opts.Services[0].Uid,
Gid: opts.Services[0].Gid,
FileMode: 0444,
}

notBefore, notAfter, _ := GetPrevRoleCertDates(optsRole, opts)
roleRequest.PrevCertNotBefore = notBefore
roleRequest.PrevCertNotAfter = notAfter
if notBefore != nil && notAfter != nil {
logutil.LogInfo(sysLogger, "Previous Role Cert Not Before date: %s, Not After date: %s", notBefore, notAfter)
}

//"rolename": "athenz.fp:role.readers"
//from the rolename, domain is athenz.fp
//role is readers
Expand All @@ -106,15 +157,7 @@ func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Op
//we have the roletoken
//write the cert to pem file using Role.Filename
roleKeyBytes := util.PrivatePem(key)
optsRole := options.Role{
Name: roleName,
Service: opts.Services[0].Name,
Filename: role.Filename,
User: "",
Uid: opts.Services[0].Uid,
Gid: opts.Services[0].Gid,
FileMode: 0444,
}

err = SaveRoleCertKey([]byte(roleKeyBytes), []byte(roleToken.Token), optsRole, opts, sysLogger)
if err != nil {
failures += 1
Expand Down Expand Up @@ -427,23 +470,27 @@ func getProviderName(provider, region, taskId, providerParentDomain string) (str
}

func extractProviderFromCert(certFile string) string {
cert, err := readCertificate(certFile)
if err != nil || cert == nil {
return ""
}
if len(cert.Subject.OrganizationalUnit) > 0 {
return cert.Subject.OrganizationalUnit[0]
}
return ""
}

func readCertificate(certFile string) (*x509.Certificate, error) {
data, err := ioutil.ReadFile(certFile)
if err != nil {
return ""
return nil, err
}
var block *pem.Block
block, _ = pem.Decode(data)
if block == nil {
return ""
return nil, nil
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return ""
}
if len(cert.Subject.OrganizationalUnit) > 0 {
return cert.Subject.OrganizationalUnit[0]
}
return ""
return x509.ParseCertificate(block.Bytes)
}

func getCertFileName(file, domain, service, certDir string) string {
Expand Down
52 changes: 41 additions & 11 deletions provider/aws/sia-eks/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"io"
"io/ioutil"
"os"

"github.com/AthenZ/athenz/clients/go/zts"
"github.com/AthenZ/athenz/libs/go/sia/aws/attestation"
"github.com/AthenZ/athenz/libs/go/sia/aws/stssession"
"github.com/AthenZ/athenz/libs/go/sia/logutil"
"github.com/AthenZ/athenz/libs/go/sia/util"
"github.com/AthenZ/athenz/provider/aws/sia-ec2/options"
"github.com/ardielle/ardielle-go/rdl"
"io"
"io/ioutil"
"os"

"github.com/aws/aws-sdk-go/service/sts"
)
Expand Down Expand Up @@ -75,23 +75,45 @@ func GetAttestationData(domain, service, account, region string, useRegionalSTS
}

func extractProviderFromCert(certFile string) string {
cert, err := readCertificate(certFile)
if err != nil || cert == nil {
return ""
}
if len(cert.Subject.OrganizationalUnit) > 0 {
return cert.Subject.OrganizationalUnit[0]
}
return ""
}

func readCertificate(certFile string) (*x509.Certificate, error) {
data, err := ioutil.ReadFile(certFile)
if err != nil {
return ""
return nil, err
}
var block *pem.Block
block, _ = pem.Decode(data)
if block == nil {
return ""
return nil, nil
}
cert, err := x509.ParseCertificate(block.Bytes)
return x509.ParseCertificate(block.Bytes)
}

func GetPrevRoleCertDates(certFile string, sysLogger io.Writer) (*rdl.Timestamp, *rdl.Timestamp, error) {
prevRolCert, err := readCertificate(certFile)
if err != nil {
return ""
return nil, nil, err
}
if len(cert.Subject.OrganizationalUnit) > 0 {
return cert.Subject.OrganizationalUnit[0]

notBefore := &rdl.Timestamp{
Time: prevRolCert.NotBefore,
}
return ""

notAfter := &rdl.Timestamp{
Time: prevRolCert.NotAfter,
}

logutil.LogInfo(sysLogger, "Existing role cert %s, not before: %s, not after: %s", certFile, notBefore.String(), notAfter.String())
return notBefore, notAfter, nil
}

func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Options, sysLogger io.Writer) bool {
Expand Down Expand Up @@ -130,6 +152,14 @@ func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Op
continue
}
roleRequest.Csr = csr

notBefore, notAfter, _ := GetPrevRoleCertDates(certFilePem, sysLogger)
roleRequest.PrevCertNotBefore = notBefore
roleRequest.PrevCertNotAfter = notAfter
if notBefore != nil && notAfter != nil {
logutil.LogInfo(sysLogger, "Previous Role Cert Not Before date: %s, Not After date: %s", notBefore, notAfter)
}

//"rolename": "athenz.fp:role.readers"
//from the rolename, domain is athenz.fp
//role is readers
Expand Down
45 changes: 38 additions & 7 deletions provider/aws/sia-fargate/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"github.com/ardielle/ardielle-go/rdl"
"io"
"io/ioutil"
"strings"
Expand Down Expand Up @@ -111,23 +112,45 @@ func GetAttestationData(domain, service, account, region, taskId string, useRegi
}

func extractProviderFromCert(certFile string) string {
cert, err := readCertificate(certFile)
if err != nil || cert == nil {
return ""
}
if len(cert.Subject.OrganizationalUnit) > 0 {
return cert.Subject.OrganizationalUnit[0]
}
return ""
}

func readCertificate(certFile string) (*x509.Certificate, error) {
data, err := ioutil.ReadFile(certFile)
if err != nil {
return ""
return nil, err
}
var block *pem.Block
block, _ = pem.Decode(data)
if block == nil {
return ""
return nil, nil
}
cert, err := x509.ParseCertificate(block.Bytes)
return x509.ParseCertificate(block.Bytes)
}

func GetPrevRoleCertDates(certFile string, sysLogger io.Writer) (*rdl.Timestamp, *rdl.Timestamp, error) {
prevRolCert, err := readCertificate(certFile)
if err != nil {
return ""
return nil, nil, err
}
if len(cert.Subject.OrganizationalUnit) > 0 {
return cert.Subject.OrganizationalUnit[0]

notBefore := &rdl.Timestamp{
Time: prevRolCert.NotBefore,
}
return ""

notAfter := &rdl.Timestamp{
Time: prevRolCert.NotAfter,
}

logutil.LogInfo(sysLogger, "Existing role cert %s, not before: %s, not after: %s", certFile, notBefore.String(), notAfter.String())
return notBefore, notAfter, nil
}

func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Options, sysLogger io.Writer) bool {
Expand Down Expand Up @@ -166,6 +189,14 @@ func GetRoleCertificate(ztsUrl, svcKeyFile, svcCertFile string, opts *options.Op
continue
}
roleRequest.Csr = csr

notBefore, notAfter, _ := GetPrevRoleCertDates(certFilePem, sysLogger)
roleRequest.PrevCertNotBefore = notBefore
roleRequest.PrevCertNotAfter = notAfter
if notBefore != nil && notAfter != nil {
logutil.LogInfo(sysLogger, "Previous Role Cert Not Before date: %s, Not After date: %s", notBefore, notAfter)
}

//"rolename": "athenz.fp:role.readers"
//from the rolename, domain is athenz.fp
//role is readers
Expand Down
Loading

0 comments on commit a7c01ee

Please sign in to comment.