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

Fix okta domain certificate #1447

Merged
merged 3 commits into from
Feb 10, 2023
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
16 changes: 16 additions & 0 deletions examples/okta_domain/datasource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
resource "okta_domain" "test" {
name = "www.example.com"
verify = false
}

data "okta_domain" "by-id" {
domain_id_or_name = okta_domain.test.id
}

data "okta_domain" "by-name" {
domain_id_or_name = "www.example.com"

depends_on = [
okta_domain.test
]
}
29 changes: 27 additions & 2 deletions examples/okta_domain_certificate/basic.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@ resource "okta_domain" "test" {
resource "okta_domain_certificate" "test" {
domain_id = okta_domain.test.id
type = "PEM"
certificate = "-----BEGIN CERTIFICATE-----\nMIIFNzCCBB+gAwIBAgISBAXomJWRama3ypu8TIxdA9wzMA0GCSqGSIb3DQEBCwUA\nMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD\nEwJSMzAeFw0yMTAyMTAwNTEzMDVaFw0yMTA1MTEwNTEzMDVaMCQxIjAgBgNVBAMT\nGWFuaXRhdGVzdC5zaWdtYW5ldGNvcnAudXMwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQC5cyk6x63iBJSWvtgsOBqIxfO8euPHcRnyWsL9dsvnbNyOnyvc\nqFWxdiW3sh2cItzYtoN1Zfgj5lWGOVXbHxP0VaNG9fHVX3+NHP6LFHQz92BzAYQm\npqi9zaP/aKJklk6LdPFbVLGhuZfm34+ijW9YsgLTKR2WTaZJK5QtamVVmP+VsSCl\na2ifFzjz2FCkMMEc/Y0zUyP+en/mbL71K+VnpZdlEC1s38EvjRTFKFZTKVw5wpWg\nCZQq/AZYj9RxR23IIuRcUJ8TQ2pyoc3kIXPWjiIarSgBlA8G9kCsxgzXP2RyLwKr\nIBIo+qyHweifpPYW28ipdSbPjiypAMdpbGLDAgMBAAGjggJTMIICTzAOBgNVHQ8B\nAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB\n/wQCMAAwHQYDVR0OBBYEFPVZKiovtIK4Av/IBUQeLUs29pT6MB8GA1UdIwQYMBaA\nFBQusxe3WFbLrlAJQOYfr52LFMLGMFUGCCsGAQUFBwEBBEkwRzAhBggrBgEFBQcw\nAYYVaHR0cDovL3IzLm8ubGVuY3Iub3JnMCIGCCsGAQUFBzAChhZodHRwOi8vcjMu\naS5sZW5jci5vcmcvMCQGA1UdEQQdMBuCGWFuaXRhdGVzdC5zaWdtYW5ldGNvcnAu\ndXMwTAYDVR0gBEUwQzAIBgZngQwBAgEwNwYLKwYBBAGC3xMBAQEwKDAmBggrBgEF\nBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwggEDBgorBgEEAdZ5AgQC\nBIH0BIHxAO8AdgBc3EOS/uarRUSxXprUVuYQN/vV+kfcoXOUsl7m9scOygAAAXeK\nkmOsAAAEAwBHMEUCIQDSudPEWXk969BT8yz3ag6BJWCMRU5tefEw9nXEQMsh5gIg\nUmfGIuUlcNNI5PydVIHj+zns+SR8P7zfd3FIxW4gK0QAdQD2XJQv0XcwIhRUGAgw\nlFaO400TGTO/3wwvIAvMTvFk4wAAAXeKkmOlAAAEAwBGMEQCIHQkr2qOGuInvonv\nW4vvdI61nraax5V6SC3E0D2JSO91AiBVhpX4BBafRAh36r7l8LrxAfxBM3CjBmAC\nq8fUrWfIWDANBgkqhkiG9w0BAQsFAAOCAQEAgGDMKXofKpDdv5kkID3s5GrKdzaj\njFmb/6kyqd1E6eGXZAewCP1EF5BVvR6lBP2aRXiZ6sJVZktoIfztZnbxBGgbPHfv\nR3iXIG6fxkklzR9Y8puPMBFadANE/QV78tIRAlyaqeSNsoxHi7ssQjHTP111B2lf\n3KmuTpsruut1UesEJcPReLk/1xTkRx262wAncach5Wp+6GWWduTZYJbsNFyrK1RP\nYQ0qYpP9wt2qR+DGaRUBG8i1XLnZS8pkyxtKhVw/a5Fowt+NqCpEBjjJiWJRSGnG\nNSgRtSXq11j8O4JONi8EXe7cEtvzUiLR5PL3itsK2svtrZ9jIwQ95wOPaA==\n-----END CERTIFICATE-----"
private_key = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5cyk6x63iBJSW\nvtgsOBqIxfO8euPHcRnyWsL9dsvnbNyOnyvcqFWxdiW3sh2cItzYtoN1Zfgj5lWG\nOVXbHxP0VaNG9fHVX3+NHP6LFHQz92BzAYQmpqi9zaP/aKJklk6LdPFbVLGhuZfm\n34+ijW9YsgLTKR2WTaZJK5QtamVVmP+VsSCla2ifFzjz2FCkMMEc/Y0zUyP+en/m\nbL71K+VnpZdlEC1s38EvjRTFKFZTKVw5wpWgCZQq/AZYj9RxR23IIuRcUJ8TQ2py\noc3kIXPWjiIarSgBlA8G9kCsxgzXP2RyLwKrIBIo+qyHweifpPYW28ipdSbPjiyp\nAMdpbGLDAgMBAAECggEAUXVfT91z6IqghhKwO8QtC5T/+fN06B8rCYSKj/FFoZL0\n0oTiLFuYwImoCadoUDQUE/Efj0rKE2LSgFHg/44IItQXE01m+5WmHmL1ADxsyoLH\nz9yDosKj7jNM7RyV8F8Bg0pL1hU+rU4rhhL/MaS0mx4eFYjC4UmcWBmXTdelSVJa\nkvXvQLT5y86bqh7tqMjM/kALTWRz5CgNJFk/ONA1yo5RTX9S7SIXimBgAvuGqP8i\nMPEhJou7U3DfzXVfvP8byqNdsZs6ZNhG3wXspl61mRyrY+51SOaNLA7Bkji7x4bH\nNw6mJI0IJTAP9oc1Z8fYeMuxT1bfuD7VOupSP0mAMQKBgQDk+KuyQkmPymeP/Wwu\nII4DUpleVzxTK9obMQQoCEEElbQ6+jTb+8ixP0bWLvBXg/rX734j7OWfn/bljWLH\nXLrSoqQZF1+XMVeY4g4wx9UuTK/D2n791zdOgQivxbIPdWL3a4ap86ar8uyMgJu8\nBLXfFBAOc+9myqUkbeO7wt0e6QKBgQDPV04jPtIJoMrggpQDNreGrANKOmsXWxj4\nOHW13QNdJ2KGQpoTdoqQ8ZmlxuA8Bf2RjHsnB2kgGVTVQR74zRib4MByhvsdhvVm\nF2LNsJoIDfqtv3c+oj13VonRUGuzUeJpwT/snyaL+jQ/ZZcYz0jDgDhIODTcFYj8\nDMSD5SHgywKBgHH6MwWuJ44TNBAiF2qyu959jGjAxf+k0ZI9iRMgYLUWjDvbdtqW\ncCWDGRDfFraJtSEuTz003GzkJPPJuIUC7OCTI1p2HxhU8ITi6itwHfdJJyk4J4TW\nT+qdIqTUpTk6tsPw23zYE3x+lS+viVZDhgEArKl1HpOthh0nMnixnH6ZAoGBAKGn\nV+xy1h9bldFk/TFkP8Jn6ki9MzGKfPVKT7vzDORcCJzU4Hu8OFy5gSmW3Mzvfrsz\n4/CR/oxgM5vwoc0pWr5thJ3GT5K93iYypX3o6q7M91zvonDa3UFl3x2qrc2pUfVS\nDhzWGJ+Z+5JSCnP1aK3EEh18dPoCcELTUYPj6X3xAoGBALAllTb3RCIaqIqk+s3Y\n6KDzikgwGM6j9lmOI2MH4XmCVym4Z40YGK5nxulDh2Ihn/n9zm13Z7ul2DJwgQSO\n0zBc7/CMOsMEBaNXuKL8Qj4enJXMtub4waQ/ywqHIdc50YaPI5Ax8dD/10h9M6Qc\nnUFLNE8pXSnsqb0eOL74f3uQ\n-----END PRIVATE KEY-----"

#certificate = file("cert.pem")
certificate = <<CERT
-----BEGIN CERTIFICATE-----
duytiennguyen-okta marked this conversation as resolved.
Show resolved Hide resolved
MIIFNzCCBB+gAwIBAgISBAXomJWRama3ypu8TIxdA9wzMA0GCSqGSIb3DQEBCwUA
...
NSgRtSXq11j8O4JONi8EXe7cEtvzUiLR5PL3itsK2svtrZ9jIwQ95wOPaA==
-----END CERTIFICATE-----
CERT

#certificate_chain = file("chain.pem")
certificate_chain = <<CHAIN
-----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
...
Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
-----END CERTIFICATE-----
CHAIN

#private_key = file("privkey.pem")
private_key = <<PK
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5cyk6x63iBJSW
...
nUFLNE8pXSnsqb0eOL74f3uQ
-----END PRIVATE KEY-----
PK
}
133 changes: 133 additions & 0 deletions okta/data_source_okta_domain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package okta

import (
"context"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/okta/okta-sdk-golang/v2/okta"
)

func dataSourceDomain() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceDomainRead,
Schema: map[string]*schema.Schema{
"domain_id_or_name": {
Type: schema.TypeString,
Required: true,
Description: "Brand ID",
},
"id": {
Type: schema.TypeString,
Computed: true,
Description: "The ID of the Domain",
},
"domain": {
Type: schema.TypeString,
Computed: true,
Description: "Domain name",
},
"certificate_source_type": {
Type: schema.TypeString,
Computed: true,
Description: "Certificate source type that indicates whether the certificate is provided by the user or Okta. Values: MANUAL, OKTA_MANAGED",
},
"validation_status": {
Type: schema.TypeString,
Computed: true,
Description: "Status of the domain. Values: NOT_STARTED, IN_PROGRESS, VERIFIED, COMPLETED",
},
"dns_records": {
Type: schema.TypeList,
Computed: true,
Description: "TXT and CNAME records to be registered for the Domain",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"expiration": {
Type: schema.TypeString,
Computed: true,
Description: "TXT record expiration",
},
"fqdn": {
Type: schema.TypeString,
Computed: true,
Description: "DNS record name",
},
"record_type": {
Type: schema.TypeString,
Computed: true,
Description: "Record type can be TXT or CNAME",
},
"values": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Description: "DNS verification value",
},
},
},
},
"public_certificate": {
Type: schema.TypeMap,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}

func dataSourceDomainRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
did, _ := d.GetOk("domain_id_or_name")
domainID := did.(string)

domains, _, err := getOktaClientFromMetadata(m).Domain.ListDomains(ctx)
if err != nil {
return diag.Errorf("failed to get domains: %v", err)
}

var domain *okta.Domain
for _, _domain := range domains.Domains {
if _domain.Id == domainID {
domain = _domain
break
}
if _domain.Domain == domainID {
domain = _domain
break
}
}
if domain == nil {
return diag.Errorf("failed to find domain by id or name: %q", domainID)
}

d.SetId(domain.Id)
d.Set("domain", domain.Domain)
d.Set("validation_status", domain.ValidationStatus)
d.Set("certificate_source_type", domain.CertificateSourceType)
arr := make([]map[string]interface{}, len(domain.DnsRecords))
for i := range domain.DnsRecords {
arr[i] = map[string]interface{}{
"expiration": domain.DnsRecords[i].Expiration,
"fqdn": domain.DnsRecords[i].Fqdn,
"record_type": domain.DnsRecords[i].RecordType,
"values": convertStringSliceToInterfaceSlice(domain.DnsRecords[i].Values),
}
}
err = setNonPrimitives(d, map[string]interface{}{"dns_records": arr})
if err != nil {
return diag.Errorf("failed to set DNS records: %v", err)
}

if domain.PublicCertificate != nil {
cert := map[string]interface{}{
"subject": domain.PublicCertificate.Subject,
"fingerprint": domain.PublicCertificate.Fingerprint,
"expiration": domain.PublicCertificate.Expiration,
}
d.Set("publice_certificate", cert)
}

return nil
}
30 changes: 30 additions & 0 deletions okta/data_source_okta_domain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package okta

import (
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceOktaDomain_read(t *testing.T) {
ri := acctest.RandInt()
mgr := newFixtureManager(domain)
config := mgr.GetFixtures("datasource.tf", ri, t)

resource.Test(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ErrorCheck: testAccErrorChecks(t),
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: config,
Destroy: false,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.okta_domain.by-id", "domain", "www.example.com"),
resource.TestCheckResourceAttr("data.okta_domain.by-name", "domain", "www.example.com"),
),
},
},
})
}
1 change: 1 addition & 0 deletions okta/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ func Provider() *schema.Provider {
behaviors: dataSourceBehaviors(),
brand: dataSourceBrand(),
brands: dataSourceBrands(),
domain: dataSourceDomain(),
emailCustomization: dataSourceEmailCustomization(),
emailCustomizations: dataSourceEmailCustomizations(),
emailTemplate: dataSourceEmailTemplate(),
Expand Down
20 changes: 0 additions & 20 deletions okta/resource_okta_domain_certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package okta

import (
"context"
"crypto/sha512"
"encoding/base64"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -37,34 +35,16 @@ func resourceDomainCertificate() *schema.Resource {
Type: schema.TypeString,
Required: true,
Description: "Certificate content",
StateFunc: func(val interface{}) string {
h := sha512.New()
h.Write([]byte(val.(string)))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
},
},
"private_key": {
Type: schema.TypeString,
Required: true,
Description: "Certificate private key",
StateFunc: func(val interface{}) string {
h := sha512.New()
h.Write([]byte(val.(string)))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
},
},
"certificate_chain": {
Type: schema.TypeString,
Required: true,
Description: "Certificate chain",
StateFunc: func(val interface{}) string {
if val.(string) == "" {
return ""
}
h := sha512.New()
h.Write([]byte(val.(string)))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
},
},
},
}
Expand Down
105 changes: 105 additions & 0 deletions okta/resource_okta_domain_certificate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package okta

import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccOktaDomainCertificate(t *testing.T) {
pwd, err := os.Getwd()
if err != nil {
t.Skip("can't get working directory from OS")
}

// NOTE: Setting up reading cert, pk, and chain files via TF file() so that
// in the future we can set up CI to get a certificate from something like
// letsencrypt.
// TF file() needs an absolute path so set up the file names and pass into a
// sprintf to interpolate a working config
domainFile := filepath.Join(pwd, "../test/fixtures/okta_domain_certificate/domain.txt")
certFile := filepath.Join(pwd, "../test/fixtures/okta_domain_certificate/cert.pem")
pkFile := filepath.Join(pwd, "../test/fixtures/okta_domain_certificate/privkey.pem")
chainFile := filepath.Join(pwd, "../test/fixtures/okta_domain_certificate/chain.pem")

for _, path := range []string{domainFile, certFile, pkFile, chainFile} {
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
t.Skip(path, "appears to not exist, skipping")
}
}

config := fmt.Sprintf(`
data "okta_domain" "test" {
domain_id_or_name = file("%s")
}

resource "okta_domain_certificate" "test" {
domain_id = data.okta_domain.test.id
type = "PEM"

certificate = file("%s")
private_key = file("%s")
certificate_chain = file("%s")
}`,
domainFile, certFile, pkFile, chainFile)
resourceName := fmt.Sprintf("%s.test", domainCertificate)

resource.Test(t, resource.TestCase{
PreCheck: testAccPreCheck(t),
ErrorCheck: testAccErrorChecks(t),
ProviderFactories: testAccProvidersFactories,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
checkIsCertificate(resourceName, "certificate"),
checkIsCertificate(resourceName, "certificate_chain"),
checkIsPrivateKey(resourceName, "private_key"),
),
},
},
})
}

func checkIsCertificate(resourceName, attribute string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("resource not found: %s", resourceName)
}
attr, ok := rs.Primary.Attributes[attribute]
if !ok {
return fmt.Errorf("resource attribute not found: %s.%s", resourceName, attribute)
}
ok, _ = regexp.MatchString("^-----BEGIN CERTIFICATE-----\n", attr)
if !ok {
return fmt.Errorf("resource %s.%s does not appear to be certificate", resourceName, attribute)
}

return nil
}
}

func checkIsPrivateKey(resourceName, attribute string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return fmt.Errorf("resource not found: %s", resourceName)
}
attr, ok := rs.Primary.Attributes[attribute]
if !ok {
return fmt.Errorf("resource attribute not found: %s.%s", resourceName, attribute)
}
ok, _ = regexp.MatchString("^-----BEGIN PRIVATE KEY-----\n", attr)
if !ok {
return fmt.Errorf("resource %s.%s does not appear to be a private key", resourceName, attribute)
}
return nil
}
}
Empty file.
Loading