Skip to content

Commit

Permalink
Merge pull request #90 from c-e-brumm/delete_after_use
Browse files Browse the repository at this point in the history
Delete all acme challenge records
  • Loading branch information
openshift-merge-robot authored Oct 22, 2019
2 parents f3d363d + fb932e6 commit 72e6a60
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
58 changes: 58 additions & 0 deletions pkg/awsclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
const (
awsCredsSecretIDKey = "aws_access_key_id"
awsCredsSecretAccessKey = "aws_secret_access_key"
resourceRecordTTL = 60
)

// Client is a wrapper object for actual AWS SDK clients to allow for easier testing.
Expand Down Expand Up @@ -78,6 +79,63 @@ func (c *awsClient) ListResourceRecordSets(input *route53.ListResourceRecordSets
return c.route53Client.ListResourceRecordSets(input)
}

// SearchForHostedZone finds a hostedzone when given an aws client and a domain string
// Returns a hostedzone object
func SearchForHostedZone(r53svc Client, baseDomain string) (hostedZone route53.HostedZone, err error) {
hostedZoneOutput, err := r53svc.ListHostedZones(&route53.ListHostedZonesInput{})
if err != nil {
return hostedZone, err
}

for _, zone := range hostedZoneOutput.HostedZones {
if strings.EqualFold(baseDomain, *zone.Name) && !*zone.Config.PrivateZone {
hostedZone = *zone
}
}
return hostedZone, err
}

// BuildR53Input contructs an Input object for a hostedzone. Contains no recordsets.
func BuildR53Input(hostedZone string) *route53.ChangeResourceRecordSetsInput {
input := &route53.ChangeResourceRecordSetsInput{
ChangeBatch: &route53.ChangeBatch{
Changes: []*route53.Change{},
},
HostedZoneId: &hostedZone,
}
return input
}

// CreateR53TXTRecordChange creates an route53 Change object for a TXT record with a given name
// and a given action to take. Valid actions are strings matching valid route53 ChangeActions.
func CreateR53TXTRecordChange(name *string, action string, value *string) (change route53.Change, err error) {
// Checking the string 'action' to see if it matches any of the valid route53 acctions.
// If an incorrect string value is passed this function will exit and raise an error.
if strings.EqualFold("DELETE", action) {
action = route53.ChangeActionDelete
} else if strings.EqualFold("CREATE", action) {
action = route53.ChangeActionCreate
} else if strings.EqualFold("UPSERT", action) {
action = route53.ChangeActionUpsert
} else {
return change, fmt.Errorf("Invaild record action passed %v. Must be DELETE, CREATE, or UPSERT", action)
}
change = route53.Change{
Action: aws.String(action),
ResourceRecordSet: &route53.ResourceRecordSet{
Name: aws.String(*name),
ResourceRecords: []*route53.ResourceRecord{
{
Value: aws.String(*value),
},
},
TTL: aws.Int64(resourceRecordTTL),
Type: aws.String(route53.RRTypeTxt),
},
}
return change, nil
}

// NewClient returns an awsclient.Client object to the caller. If NewClient is passed a non-null
// secretName, an attempt to retrieve the secret from the namespace argument will be performed.
// AWS credentials are returned as these secrets and a new session is initiated prior to returning
Expand Down
59 changes: 59 additions & 0 deletions pkg/controller/certificaterequest/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/go-logr/logr"

certmanv1alpha1 "github.com/openshift/certman-operator/pkg/apis/certman/v1alpha1"
"github.com/openshift/certman-operator/pkg/awsclient"
)

// AnswerDnsChallenge constructs a fqdn from acmeChallengeSubDomain and domain. An route53 AWS client is then spawned to retrieve HostedZones.
Expand Down Expand Up @@ -271,6 +272,64 @@ func (r *ReconcileCertificateRequest) DeleteAcmeChallengeResourceRecords(reqLogg
return nil
}

// DeleteAllAcmeChallengeResourceRecords to delete all records in a hosted zone that begin with the prefix defined by the const acmeChallengeSubDomain
func (r *ReconcileCertificateRequest) DeleteAllAcmeChallengeResourceRecords(reqLogger logr.Logger, cr *certmanv1alpha1.CertificateRequest) error {
// This function is for record clean up. If we are unable to find the records to delete them we silently accept these errors
// without raising an error. If the record was already deleted that's fine.

r53svc, err := r.getAwsClient(cr)
if err != nil {
return err
}

// Make sure that the domain ends with a dot.
baseDomain := cr.Spec.ACMEDNSDomain
if string(baseDomain[len(baseDomain)-1]) != "." {
baseDomain = baseDomain + "."
}

// Calls function to get the hostedzone of the domain of our CertificateRequest
hostedzone, err := awsclient.SearchForHostedZone(r53svc, baseDomain)
if err != nil {
reqLogger.Error(err, "Unable to find appropriate hostedzone.")
return err
}

// Get a list of RecordSets from our hostedzone that match our search criteria
// Criteria - record name starts with our acmechallenge prefix, record is a TXT type
listRecordSets, err := r53svc.ListResourceRecordSets(&route53.ListResourceRecordSetsInput{
HostedZoneId: aws.String(*hostedzone.Id), // Required
StartRecordName: aws.String(acmeChallengeSubDomain + "*"),
StartRecordType: aws.String(route53.RRTypeTxt),
})
if err != nil {
reqLogger.Error(err, "Unable to retrieve acme records for hostedzone.")
return err
}

// Construct an Input object and populate it with records we intend to change
// In this case we're adding all acme challenge records found above and setting their action to Delete
input := awsclient.BuildR53Input(*hostedzone.Id)
for _, record := range listRecordSets.ResourceRecordSets {
if strings.Contains(*record.Name, acmeChallengeSubDomain) {
change, err := awsclient.CreateR53TXTRecordChange(record.Name, route53.ChangeActionDelete, record.ResourceRecords[0].Value)
if err != nil {
reqLogger.Error(err, "Error creating record change object")
}
input.ChangeBatch.Changes = append(input.ChangeBatch.Changes, &change)
}
}

// Sent the completed Input object to Route53 to delete the acme records
result, err := r53svc.ChangeResourceRecordSets(input)
if err != nil {
reqLogger.Error(err, result.GoString())
return nil
}

return nil
}

// func newTXTRecordSet(fqdn, value string, ttl int) *route53.ResourceRecordSet {
// return &route53.ResourceRecordSet{
// Name: aws.String(fqdn),
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/certificaterequest/issue_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func (r *ReconcileCertificateRequest) IssueCertificate(reqLogger logr.Logger, cr

// After resolving all new challenges, and storing the cert, delete the challenge records
// that were used from dns in this zone.
err = r.DeleteAcmeChallengeResourceRecords(reqLogger, cr)
err = r.DeleteAllAcmeChallengeResourceRecords(reqLogger, cr)
if err != nil {
reqLogger.Error(err, "error occurred deleting acme challenge resource records from Route53")
}
Expand Down

0 comments on commit 72e6a60

Please sign in to comment.