Günümüzde TLS sertifikası koruması olmayan, genel API uç noktalarına sahip sistemleri hayal etmek zor. Sertifika vermenin birkaç yolu vardır:
Bu yazı kapsamında, yalnızca AWS hizmetleri tarafından değil, esas olarak AWS içinde kullanılabilecek ücretsiz sertifikalardan bahsedeceğim. Açıkça görülüyor ki, yalnızca yönetilen AWS hizmetlerini kullanıyorsanız ve sıkı güvenlik gereksinimleriniz yoksa, AWS Sertifika Yöneticisi dışında bir şey kullanmanın bir anlamı yoktur. AWS Sertifika Yöneticisi, DNS veya HTTP sorgulamaları yoluyla sertifika vermenin çok kullanışlı ve hızlı bir yöntemini sunar; ancak bu sertifikaları, fiziksel sertifika dosyası gerektiren Nginx çalıştıran bir EC2 bulut sunucusu gibi AWS hizmetlerinin (API Ağ Geçidi, ALB, NLB vb.) dışında kullanmanız gerekirse temel AWS sınırlamalarıyla karşılaşırsınız. Ayrıca siz talep etseniz bile AWS Sertifika Yöneticisi sertifika içeriğini görüntülemez.
Bu noktada, en azından buluta bağlı olmadığı için, Sertifika Yöneticisi'nden daha yaygın olarak kullanılan bir araç olan LetsEncrypt'i hatırlatmanın tam zamanı. Maalesef AWS'de yerleşik bir LetsEncrypt sertifikası verme tekniği mevcut değildir. EC2 veya ECS hizmetleriniz için sertifika aracını kullanmak mümkündür ancak bu senaryoda yenileme sürecini nasıl yapılandıracağınızı düşünmeniz gerekecektir. Ayrıca farklı stratejileri birleştirmek istemiyorum çünkü tüm sistem karmaşıklığını azaltacağı için her şey için tek bir prosedüre sahip olmanın daha iyi olduğunu düşünüyorum.
Bunu dikkate alarak LetsEncrypt sertifikalarını karmaşık yapılandırma gerektirmeden otomatik olarak yayınlayan ve yenileyen bir Lambda işlevi oluşturdum. Sertifika, ilk sertifika verildikten sonra AWS Sertifika Yöneticisi sertifikalarıyla birlikte ARN kullanan herhangi bir AWS hizmetinde kullanılabilir. Ayrıca, ister Nginx çalıştıran bir EC2 bulut sunucusu olsun ister başka bir yer olsun, seçtiğiniz herhangi bir konumda AWS Secrets Manager'da saklanan bir fiziksel sertifika sürümünü kullanabilirsiniz.
Bu yazıda DNS bölgenizin AWS Route53 tarafından yönetildiğini varsayacağım.
Bu makalede açıklanan Lambda işlevi Go v1.22'de yazılmıştır. DNS kayıtları, gizli diziler veya sertifikalar gibi tüm sonuç kaynakları, varsayılan olarak Terraform kodu aracılığıyla oluşturulan Amazon IAM rolü tarafından kontrol edilir. Lambda eylemlerinin sırası aşağıdaki gibidir:
aws_cloudwatch_event_target
aracılığıyla gerçekleştirilen cron tarafından yürütmenin bir sonucu olabilir. Etkinlik örneği: { "domainName": "hackernoon.referrs.me", "acmeUrl": "prod", "acmeEmail": "[email protected]", "reImportThreshold": 10, "issueType": "default", "storeCertInSecretsManager" : true }
reImportThreshold
değerinden azsa LetsEncrypt DNS-01
sorgulamasını başlatın. Bu adım Lambda'nın alan adını AWS Route53 bölgesiyle eşleştiren bir TXT
kaydı oluşturmasını ve sertifikanızın hazır olmasını beklemesini içerir.storeCertInSecretsManager
doğruysa Lambda, sertifika dosyalarını AWS Secrets Manager'ın içinde saklar.
Kod
Lambda Go 1.22'de yazılmıştır. Mümkün olduğunca az kitaplık kullanmak, kodu kuru tutma hedefimi korumama yardımcı oldu. Gerekli go kitaplıklarının tam listesi:
URL'si | Tanım |
---|---|
Go geliştiricilerinin AWS Lambda işlevlerini geliştirmesine yardımcı olacak kitaplıklar, örnekler ve araçlar. | |
Go programlama dili için AWS SDK. | |
LetsEncrypt / ACME istemcisi ve kütüphanesi. | |
Null olabilen değerlerin makul şekilde işlenmesi. | |
Go için yapılandırılmış, takılabilir günlük kaydı. |
Docker görüntüsü
Temel liman işçisi görüntüsü olarak gcr.io/distroless/static:nonroot kullandım. Libc gerektirmeyen Go uygulamaları için bu görüntü mükemmeldir. Tamamen scratch
ibaret değildir ve şunları içerir:
Oluşturma süreci
Büyük yazılım projelerinde oluşturma sürecini denetlemek zahmetli ve zaman alıcı bir işe dönüşebilir. Makefiles, projenizin verimli ve tutarlı bir şekilde oluşturulmasını sağlayarak bu süreci otomatikleştirmeye ve kolaylaştırmaya yardımcı olabilir. Bu nedenle tüm Golang projelerimde Makefile kullanmayı tercih ediyorum. Dosya basit:
##@ General help: ## Display this help. @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) fmt: ## Run go fmt against code. go fmt ./... vet: ## Run go vet against code. go vet ./... ##@ Build build: fmt vet ## Build service binary. go build -o bin/lambda main.go run: vet ## Run service from your laptop. go run ./main.go ##@ Test lint: ## Run Go linter golangci-lint run ./... test: ## Run Go tests go test ./...
CICD tarafından Go uygulaması için tipik kurulumu kullandım
Sürekli entegrasyon olarak GitHub Eylemleri .
Docker kayıt defteri olarak ghcr.io. DockerHub ile karşılaştırıldığında bu, onu kullanmayı tercih eden iki temel özellik sunuyor:
kvendingoldo/semver-action : Otomatik sürüm oluşturma için GitHub Eylemleri eklentim. Depo taahhütleri için SemVer uyumlu etiketler üreten bir GitHub eylemidir. Eylem, sürümleri yönetebilir, GitHub sürümleri oluşturabilir ve depo içindeki sürüm dallarını kontrol edebilir. Hem tek hem de monorepolarla harika çalışır.
Otomatik değişiklik günlüğü oluşturma. Değişiklik günlüklerinden keyif alıyorum! Yönettiğim diğer Açık Kaynak projeleri bağlamında (örneğin, https://github.com/tofuutils/tenv , https://github.com/tofuutils/tofuenv vb.), ekibim kullanıcıları şu konularda bilgilendirmenin önemini fark etti: değişiklikler.
golangci-lint . Benim bakış açıma göre tüm kodlar statik bir kod analizörü tarafından incelenmelidir. SonarQube tüm projeler için kurulamaz, ancak golangci bence küçük ve orta ölçekli Go projeleri için yeterlidir.
Bu sayfada tartışılan kod Terraform ve OpenTofu için aynıdır, ancak Terraform v1.6'dan başlayarak Hashicorp, Terraform lisansını Business Source License (BSL) v1.1 olarak değiştirmiştir. Terraform, en kısa sürede OpenTofu'ya geçin.
OpenTofu veya Terraform'un birden fazla sürümünü yönetmeniz gerekiyorsa,
Daha fazla Terraform/OpenTofu örneğini Git deposundaki örnekler klasöründe bulabilirsiniz.
AWS LetsEncrypt Lambda ile OpenTofu aracılığıyla çalışmak için aşağıdaki adımları uygulamanız gerekir:
OpenTofu/Terraform kodunuza modül ekleyin
module "letsencrypt_lambda" { source = "[email protected]:kvendingoldo/aws-letsencrypt-lambda.git//files/terraform/module?ref=0.31.4" blank_name = "kvendingoldo-letsencrypt-lambda" tags = var.tags cron_schedule = var.letsencrypt_lambda_cron_schedule events = var.letsencrypt_lambda_events ecr_proxy_username = var.ecr_proxy_username ecr_proxy_access_token = var.ecr_proxy_access_token }
Değişkenleri belirtin
variable "tags" { default = { hackernoon : "demo" } } variable "ecr_proxy_username" { default = "kvendingoldo" } variable "ecr_proxy_access_token" { default = "ghp_xxx" } variable "letsencrypt_lambda_cron_schedule" { default = "rate(168 hours)" } variable "letsencrypt_lambda_events" { default = [ { "acmRegion" : "us-east-1", "route53Region" : "us-east-1", "domainName" : "hackernoon.referrs.me", "acmeUrl" : "stage", "acmeEmail" : "[email protected]", "reImportThreshold" : 100, "issueType" : "default", "storeCertInSecretsManager" : false } ] }
ecr_proxy_username
ve ecr_proxy_access_token
değişkenlerine dikkat edin. AWS Lambda, varsayılan olarak AWS ECR dışındaki kaynaklardan görüntü çekemez. Neyse ki AWS ekibi, DockerHub veya GHCR gibi halka açık kayıtlardan görüntüleri alıp ECR'de saklayabilen ECR Proxy önbelleği oluşturdu. Bu olasılığa rağmen AWS, halka açık depolardan bile görüntülerin belirteç olmadan çekilmesine izin vermez; bu nedenle, önceden oluşturulmuş Docker görüntülerine erişim kazanmak için kişisel bir GitHub belirteci edinmeniz gerekir. Alternatif olarak GitHub depomu çekebilir, görüntüyü yerel olarak oluşturabilir ve ardından mevcut ECR deponuza yükleyebilirsiniz. Bu senaryoda örnek şu şekilde değiştirilebilir:
module "letsencrypt_lambda" { source = "../../" blank_name = "kvendingoldo-letsencrypt-lambda" tags = var.tags cron_schedule = var.letsencrypt_lambda_cron_schedule events = var.letsencrypt_lambda_events ecr_proxy_enabled = false ecr_image_uri = "<YOUR_ACCOUNT_ID>.dkr.ecr.us-east-2.amazonaws.com/aws_letsencrypt_lambda:<VERSION>" }
Kodu değiştirmeyi tamamladığınızda, OpenTofu sürüm değiştirici tenv ile OpenTofu'yu yüklemek için aşağıdaki komutu çalıştırın:
$ tenv tofu install
Ve son olarak üretilen kodu uygulamak için aşağıdaki komutları uygulayın:
$ tofu init $ tofu plan $ tofu apply
Kod AWS'ye dağıtılana ve olaylar tetiklenene kadar bekleyin. Birkaç dakika sonra sertifika yöneticisinin içinde hazır sertifikaları göreceksiniz. Örnek:
AWS, şu andan itibaren verilen sertifikayı ARN'nin sunduğu tüm hizmetlerde kullanabilir.
Sertifikayı AWS hizmetlerinin dışında kullanmanız veya içeriğine erişiminiz olması gerekiyorsa storeCertInSecretsManager
olay seçeneğini true
olarak ayarlayın. Bu durumda Lambda temel yürütmeyi tamamladığında sertifika AWS Secrets Manager'a kaydedilecektir. Kullanıcılara daha fazla esneklik sağlar: Sertifikanın içeriğini inceleyebilir, doğrudan EC2'den onunla çalışabilir vb.. AWS Secrets Manager hakkında daha fazla bilgi edinmek için resmi kılavuzu okuyun.
İsim | Tanım | Olası değerler | Varsayılan değer | Örnek | Gerekli |
---|---|---|---|---|---|
| Günlükler için biçimlendirici türü | JSON | METİN | METİN | JSON | ❌ |
| Uygulama modu. AWS yürütmesi için | bulut | yerel | bulut | bulut | ✅ |
| Günlük düzeyi | panik|ölümcül|hata|uyarı|bilgi|hata ayıklama|izleme | uyarmak | uyarmak | ❌ |
| Varsayılan AWS Bölgesi. AWS'ye dağıtımdan sonra otomatik olarak ayarlanır. | <geçerli herhangi bir AWS bölgesi> | - | abd-doğu-1 | ✅ |
| Sertifikanın verildiği veya yenilendiği alan adı | geçerli herhangi bir alan adı | - | hacker öğlen. beni yönlendiren | ✅ |
| | ürün | sahne | dürtükleme | dürtükleme | ✅ |
| LetsEncrypt sertifikasına bağlı e-posta adresi | geçerli herhangi bir e-posta | ✅ | ||
| Sertifikanın geçerlilik süresi (TTL) | herhangi bir int > 0 | 10 | 10 | ✅ |
| | “doğru” | "YANLIŞ" | "YANLIŞ" | "YANLIŞ" | ❌ |
aws-letsencrypt-lambda ile çalışma kapsamında zaman zaman günlükleri incelemek isteyebilirsiniz. Bunu başarmak oldukça kolaydır:
/aws/lambda/kvendingoldo-letsencrypt-lambda
OpenTofu aracılığıyla oluşturulan Lambda fonksiyonuna gidin. “Testler” butonuna tıklayın.
Test Event
doldurun ve Test
tıklayın
{ "domainName": "<YOUR_VALID_DOMAIN>", "acmeUrl": <stage | prod>, "acmeEmail": "<ANY_VALID_EMAIL>", "reImportThreshold": 10, "issueType": "<default | force>", "storeCertInSecretsManager" : <true | false> }
Örnek 1:
{ "domainName": "hackernoon.referrs.me", "acmeUrl": "prod", "acmeEmail": "[email protected]", "reImportThreshold": 10, "issueType": "default" }
Yürütme tamamlanıncaya kadar bekleyin. Yürütme günlüğünün Cloudwatch'ta mevcut olmasını sağlayabilirsiniz. Genellikle ilk sorun yaklaşık 5 dakika sürer.
https://github.com/kvendingoldo/aws-letsencrypt-lambda deposunu dizüstü bilgisayarınıza kopyalayın
AWS Cli kimlik bilgilerini resmi kılavuz aracılığıyla yapılandırın.
Ortam değişkenleri bölümünü inceleyin ve gereken minimum değişken sayısını ayarlayın. LetsEncrypt, ACME_URL="prod"
için saat başına yeniden deneme miktarını sınırlayacağından, test için ACME_URL="stage"
kullanılmasını öneririm. Ortam değişkenleri örneği:
export AWS_REGION="us-east-2" export MODE=local export DOMAIN_NAME="hackernoon.referrs.me" export ACME_URL="stage" export ACME_EMAIL="[email protected]" export REIMPORT_THRESHOLD=10 export ISSUE_TYPE="default" export STORE_CERT_IN_SECRETSMANAGER="true"
Lambda'yı aşağıdaki komutla yerel olarak yürütün:
go run main.go
Lambda'nın başarılı bir şekilde yürütülmesinin ardından aşağıdaki günlük görünecektir.
INFO[0000] Starting lambda execution ... INFO[0000] Lambda will use STAGING ACME URL; If you need to use PROD URL specify it via 'ACME_URL' or pass in event body INFO[0000] Certificate found, arn is arn:aws:acm:us-east-2:004867756392:certificate/72f872fd-e577-43f4-ae38-6833962630af. Trying to renew ... INFO[0000] Checking certificate for domain 'hackernoon.referrs.me' with arn 'arn:aws:acm:us-east-2:004867756392:certificate/72f872fd-e577-43f4-ae38-6833962630af' INFO[0000] Certificate status is 'ISSUED' INFO[0000] Certificate in use by [] INFO[0000] Certificate valid until 2024-08-31 13:50:49 +0000 UTC (89 days left) INFO[0000] Try to get certificate for hackernoon.referrs.me domain 2024/06/02 17:56:23 [INFO] acme: Registering account for [email protected] 2024/06/02 17:56:24 [INFO] [hackernoon.referrs.me, www.hackernoon.referrs.me] acme: Obtaining bundled SAN certificate 2024/06/02 17:56:25 [INFO] [hackernoon.referrs.me] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/12603809394 2024/06/02 17:56:25 [INFO] [www.hackernoon.referrs.me] AuthURL: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/12603809404 2024/06/02 17:56:25 [INFO] [hackernoon.referrs.me] acme: Could not find solver for: tls-alpn-01 2024/06/02 17:56:25 [INFO] [hackernoon.referrs.me] acme: Could not find solver for: http-01 2024/06/02 17:56:25 [INFO] [hackernoon.referrs.me] acme: use dns-01 solver 2024/06/02 17:56:25 [INFO] [www.hackernoon.referrs.me] acme: Could not find solver for: tls-alpn-01 2024/06/02 17:56:25 [INFO] [www.hackernoon.referrs.me] acme: Could not find solver for: http-01 2024/06/02 17:56:25 [INFO] [www.hackernoon.referrs.me] acme: use dns-01 solver 2024/06/02 17:56:25 [INFO] [hackernoon.referrs.me] acme: Preparing to solve DNS-01 2024/06/02 17:56:26 [INFO] Wait for route53 [timeout: 5m0s, interval: 4s] 2024/06/02 17:57:00 [INFO] [www.hackernoon.referrs.me] acme: Preparing to solve DNS-01 2024/06/02 17:57:00 [INFO] Wait for route53 [timeout: 5m0s, interval: 4s] 2024/06/02 17:57:30 [INFO] [hackernoon.referrs.me] acme: Trying to solve DNS-01 2024/06/02 17:57:30 [INFO] [hackernoon.referrs.me] acme: Checking DNS record propagation. [nameservers=109.122.99.130:53,109.122.99.129:53] 2024/06/02 17:57:34 [INFO] Wait for propagation [timeout: 5m0s, interval: 4s] 2024/06/02 17:57:46 [INFO] [hackernoon.referrs.me] The server validated our request 2024/06/02 17:57:46 [INFO] [www.hackernoon.referrs.me] acme: Trying to solve DNS-01 2024/06/02 17:57:46 [INFO] [www.hackernoon.referrs.me] acme: Checking DNS record propagation. [nameservers=109.122.99.130:53,109.122.99.129:53] 2024/06/02 17:57:50 [INFO] Wait for propagation [timeout: 5m0s, interval: 4s] 2024/06/02 17:58:30 [INFO] [www.hackernoon.referrs.me] The server validated our request 2024/06/02 17:58:30 [INFO] [hackernoon.referrs.me] acme: Cleaning DNS-01 challenge 2024/06/02 17:58:30 [INFO] Wait for route53 [timeout: 5m0s, interval: 4s] 2024/06/02 17:59:09 [INFO] [www.hackernoon.referrs.me] acme: Cleaning DNS-01 challenge 2024/06/02 17:59:09 [INFO] Wait for route53 [timeout: 5m0s, interval: 4s] 2024/06/02 17:59:43 [INFO] [hackernoon.referrs.me, www.hackernoon.referrs.me] acme: Validations succeeded; requesting certificates 2024/06/02 17:59:43 [INFO] Wait for certificate [timeout: 30s, interval: 500ms] 2024/06/02 17:59:45 [INFO] [hackernoon.referrs.me] Server responded with a certificate. INFO[0203] Certificate has been successfully imported. Arn is arn:aws:acm:us-east-2:004867756392:certificate/72f872fd-e577-43f4-ae38-6833962630af INFO[0204] Secret updated successfully. SecretId: arn:aws:secretsmanager:us-east-2:004867756392:secret:hackernoon.referrs.me-NioT77 INFO[0204] Lambda has been completed
İşte bu. AWS, şu andan itibaren verilen sertifikayı ARN'nin herhangi bir hizmetinde veya fiziksel olarak gerekli olduğu diğer yerlerde AWS Secrets Manager'dan alarak kullanabilir.
Üretimde Lambda işlevini neredeyse dört yıldır kullanıyorum. Yıllar geçtikçe, ilk uygulamanın çeşitli yönleri değişti:
Daha önce AWS, ECR dışı kayıtların Lambda kaynağı olarak kullanılmasını yasaklıyordu. Bu değişmedi ancak AWS, GitHub, DockerHub ve birkaç ek kayıt için ECR proxy'sini ekledi. Bu işlevsellik olmadan Lambda görüntülerini kişisel ECR'mize manuel olarak göndermek ve URL'yi Terraform kodundaki görüntünün URL'siyle değiştirmek zorunda kaldık. Artık OpenTofu kodu bunu ECR Proxy aracılığıyla otomatik olarak yapıyor.
Başlangıçta http-01
veya tls-alpn-01
gibi çeşitli zorluklar getirmeyi düşündüm ama dört yıl boyunca kimse beni bu konuda sorgulamadı. GitHub konularında hala mevcuttur ve eğer bu yetenek gerekiyorsa, onu oluşturmak için birlikte çalışabiliriz.
Proje ilk başladığında LetsEncrypt sertifikalarını saf EC2 bulut sunucularında kullanmak istemedim, ancak bugünlerde bu standart bir uygulamadır. Daha önce de belirttiğim gibi bazı durumlarda AWS cli kullanılarak AWS Secrets Managed'den sertifika alınabilir.
Yıllar boyunca pek çok yeni Go kodu yazdım, dolayısıyla depomdaki orijinal Lambda kodunun olabileceği kadar şık olmadığını söyleyebilirim. Onunla en son Go projem olan tenv (Go'da yazılmış OpenTofu, Terraform, Terragrunt ve Atmos sürüm yöneticisi) arasında önemli bir fark var, ancak her durumda kod hala genel olarak destekleniyor, bu nedenle üzerinde değişiklik yapmak kazandı çok problemli olmasın. Bazen kodu daha şık hale getirmek için önemli yeniden düzenleme işlemleri yapacağım.
Yıllardır aynı Lambda birçok farklı projede kullanılıyor. Ayrıca ekibimizin otomasyon süreçlerini basitleştirmek için AWS LetsEncrypt Lambda'yı kullanarak tüm müşterilerimiz için TLS sertifikalarını yönettiği cloudexpress.app DevOps platformunun kurucu ortağıyım.
Şimdi rakamlardan bahsedelim. 4 yıllık bir süre boyunca bu proje birçok kişiye yardımcı oldu ve çok sayıda Açık Kaynak ve 30'un üzerinde ticari projede kullanıldı. Lambda 2000'den fazla sertifika veriyor ve bununla yetinmek istemiyor.
AWS LetsEncrypt Lambda sizin için uygun bir çözümdür:
Bu noktalardan en az birinin sizin durumunuz için geçerli olduğunu fark ettiyseniz AWS Lambda'yı kullanabilirsiniz. Ayrıca geliştirmeye katılmak isterseniz GitHub'da yeni konulara ve Çekme İsteklerine her zaman açığım. Proje URL'si: https://github.com/kvendingoldo/aws-letsencrypt-lambda .