Skip to content

Commit dc5e80e

Browse files
committed
sync standalone domain and SSL certificate
1 parent a504773 commit dc5e80e

File tree

6 files changed

+158
-3
lines changed

6 files changed

+158
-3
lines changed

src/Commands/SyncCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public function handle(): void
3535
Commands\SyncMultitenancyTenantsCommand::class,
3636
]
3737
: [
38-
// Commands\SyncStandaloneCommand::class,
38+
Commands\SyncStandaloneCommand::class,
3939
],
4040
Commands\SyncComputeCommand::class,
4141
Commands\SyncCiCommand::class,

src/Commands/SyncStandaloneCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
class SyncStandaloneCommand extends SteppedCommand
99
{
1010
protected array $steps = [
11-
// Steps\Standalone\SyncHostedZoneStep::class,
12-
// Steps\Standalone\SyncSslCertificateStep::class,
11+
Steps\Standalone\SyncHostedZoneStep::class,
12+
Steps\Standalone\SyncSslCertificateStep::class,
1313
Steps\Standalone\SyncQueueStep::class,
1414
Steps\Standalone\SyncQueueAlarmStep::class,
1515
];
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace Codinglabs\Yolo\Concerns;
4+
5+
use Codinglabs\Yolo\Aws;
6+
use Codinglabs\Yolo\AwsResources;
7+
8+
trait SyncsSslCertificates
9+
{
10+
protected function requestCertificate(string $apex): void
11+
{
12+
$certificate = Aws::acm()->requestCertificate([
13+
'DomainName' => $apex,
14+
'SubjectAlternativeNames' => ["*.{$apex}"],
15+
'ValidationMethod' => 'DNS',
16+
]);
17+
18+
$this->validateCertificate($certificate['CertificateArn'], $apex);
19+
}
20+
21+
protected function validateCertificate(string $certificateArn, string $apex): void
22+
{
23+
do {
24+
$certificate = Aws::acm()->describeCertificate([
25+
'CertificateArn' => $certificateArn,
26+
])['Certificate'];
27+
28+
// take a little snooze because the AWS result
29+
// is incomplete on the first request
30+
sleep(2);
31+
} while (
32+
! array_key_exists('DomainValidationOptions', $certificate) ||
33+
! collect($certificate['DomainValidationOptions'])
34+
->every(fn (array $option) => array_key_exists('ResourceRecord', $option))
35+
);
36+
37+
Aws::route53()->changeResourceRecordSets([
38+
'ChangeBatch' => [
39+
'Changes' => collect($certificate['DomainValidationOptions'])
40+
->filter(fn (array $option) => $option['ValidationMethod'] === 'DNS'
41+
&& ! str_starts_with($option['ValidationDomain'], '*'))
42+
->map(function (array $option) {
43+
return [
44+
'Action' => 'UPSERT',
45+
'ResourceRecordSet' => [
46+
'Name' => $option['ResourceRecord']['Name'],
47+
'Type' => $option['ResourceRecord']['Type'],
48+
'ResourceRecords' => [
49+
[
50+
'Value' => $option['ResourceRecord']['Value'],
51+
],
52+
],
53+
'TTL' => 300,
54+
],
55+
];
56+
})->toArray(),
57+
'Comment' => 'Created by yolo CLI',
58+
],
59+
'HostedZoneId' => AwsResources::hostedZone($apex)['Id'],
60+
]);
61+
62+
// wait for the certificate to be issued
63+
$certificate = AwsResources::certificate($apex);
64+
65+
if ($certificate['Status'] !== 'ISSUED') {
66+
do {
67+
$certificate = AwsResources::certificate($apex);
68+
69+
// take a little snooze until the certificate is issued
70+
sleep(2);
71+
} while ($certificate['Status'] !== 'ISSUED');
72+
}
73+
}
74+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
namespace Codinglabs\Yolo\Contracts;
4+
5+
interface ExecutesDomainStep extends Step {}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Codinglabs\Yolo\Steps\Standalone;
4+
5+
use Codinglabs\Yolo\Aws;
6+
use Illuminate\Support\Arr;
7+
use Illuminate\Support\Str;
8+
use Codinglabs\Yolo\Manifest;
9+
use Codinglabs\Yolo\AwsResources;
10+
use Codinglabs\Yolo\Enums\StepResult;
11+
use Codinglabs\Yolo\Contracts\ExecutesDomainStep;
12+
use Codinglabs\Yolo\Exceptions\ResourceDoesNotExistException;
13+
14+
class SyncHostedZoneStep implements ExecutesDomainStep
15+
{
16+
public function __invoke(array $options): StepResult
17+
{
18+
try {
19+
AwsResources::hostedZone(Manifest::apex());
20+
21+
return StepResult::SYNCED;
22+
} catch (ResourceDoesNotExistException) {
23+
if (! Arr::get($options, 'dry-run')) {
24+
Aws::route53()->createHostedZone([
25+
'CallerReference' => Str::uuid(),
26+
'Name' => Manifest::apex(),
27+
]);
28+
29+
return StepResult::CREATED;
30+
}
31+
32+
return StepResult::WOULD_CREATE;
33+
}
34+
}
35+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Codinglabs\Yolo\Steps\Standalone;
4+
5+
use Illuminate\Support\Arr;
6+
use Codinglabs\Yolo\Manifest;
7+
use Codinglabs\Yolo\AwsResources;
8+
use Codinglabs\Yolo\Enums\StepResult;
9+
use Codinglabs\Yolo\Contracts\ExecutesDomainStep;
10+
use Codinglabs\Yolo\Concerns\SyncsSslCertificates;
11+
use Codinglabs\Yolo\Exceptions\ResourceDoesNotExistException;
12+
13+
class SyncSslCertificateStep implements ExecutesDomainStep
14+
{
15+
use SyncsSslCertificates;
16+
17+
public function __invoke(array $options): StepResult
18+
{
19+
try {
20+
$certificate = AwsResources::certificate(Manifest::apex());
21+
22+
if ($certificate['Status'] === 'PENDING_VALIDATION') {
23+
if (! Arr::get($options, 'dry-run')) {
24+
$this->validateCertificate($certificate['CertificateArn'], Manifest::apex());
25+
} else {
26+
return StepResult::WOULD_SYNC;
27+
}
28+
}
29+
30+
return StepResult::SYNCED;
31+
} catch (ResourceDoesNotExistException) {
32+
if (! Arr::get($options, 'dry-run')) {
33+
$this->requestCertificate(Manifest::apex());
34+
35+
return StepResult::CREATED;
36+
}
37+
38+
return StepResult::WOULD_CREATE;
39+
}
40+
}
41+
}

0 commit comments

Comments
 (0)