Skip to content

Commit 0e56679

Browse files
authored
Adding JKS creation along with the certificates (#17)
1 parent 2437d03 commit 0e56679

File tree

8 files changed

+300
-53
lines changed

8 files changed

+300
-53
lines changed

docs/certificates.rst

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
.. meta::
3+
:description: Files Composer features
4+
:keywords: AWS, Kubernetes, SSL, certificates
5+
6+
7+
.. _certificates
8+
9+
===================
10+
SSL Certificates
11+
===================
12+
13+
Self signed certificates
14+
============================
15+
16+
When deploying services, it is best practice where possible to enable TLS termination. Even when the certificates are
17+
self-signed, this improves security dramatically. With the files composer, you can request to generate certificates on
18+
the fly to later use with your application. This will create a private key and public certificate.
19+
20+
Below are optional properties and there default values that you can set so that the certificate information reflects
21+
your needs.
22+
23+
+----------------------+---------------------------------------------+
24+
| Property Name | Default Value |
25+
+======================+=============================================+
26+
| emailAddress | [email protected] |
27+
+----------------------+---------------------------------------------+
28+
| commonName | the hostname retrieved from the os.hostname |
29+
+----------------------+---------------------------------------------+
30+
| countryName | ZZ |
31+
+----------------------+---------------------------------------------+
32+
| localityName | Anywhere |
33+
+----------------------+---------------------------------------------+
34+
| stateOrProvinceName | Shire |
35+
+----------------------+---------------------------------------------+
36+
| organizationName | NoOne |
37+
+----------------------+---------------------------------------------+
38+
| organizationUnitName | Automation |
39+
+----------------------+---------------------------------------------+
40+
| validityEndInSeconds | 3*31*24*60*60=3Months |
41+
+----------------------+---------------------------------------------+
42+
43+
.. note::
44+
45+
The certificates are created once, and not automatically renewed after ``validityEndInSeconds`` expires.
46+
This is meant to be a solution to provision temporary certificates.
47+
48+
There is no CA created and retrievable in this process.
49+
50+
jksConfig
51+
------------
52+
53+
This is a configuration option that allows you to create a java key store (JKS) in the JKS format from the generated
54+
certificate files. You can specify the fileName which will be created in the same folder, alongside the key and certificate.
55+
You must specify a passphrase, which is used for both the private key and the jks encryption.
56+
57+
58+
.. code-block::
59+
60+
certificates:
61+
x509:
62+
/tmp/testing:
63+
keyFileName: nginx.key
64+
certFileName: nginx.crt
65+
commonName: test.net
66+
jksConfig:
67+
fileName: test.jks
68+
passphrase: somesecretpassword

docs/features.rst

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ AWS Secrets Manager Source
5252
.. attention::
5353

5454
This should only be used for very edgy use-cases, such as retrieving certificates stored as flat content in AWS SSM.
55-
You should absolutely use the `AWS ECS Task Definition Secrets`_ definitions
55+
Alternatively you can use the `AWS ECS Task Definition Secrets`_ definitions
5656

5757
.. seealso::
5858

@@ -70,6 +70,23 @@ accessible.
7070
We do not recommend to put the basic auth credentials in plain text in the configuration, unless the source
7171
of the configuration for ECS Files Composer comes from AWS Secrets manager.
7272

73+
Self-signed certificates rendering
74+
====================================
75+
76+
.. code-block::
77+
78+
certificates:
79+
x509:
80+
/tmp/testinggg:
81+
keyFileName: nginx.key
82+
certFileName: nginx.crt
83+
commonName: test.net
84+
85+
.. seealso::
86+
87+
More details on all the available options for :ref:`certificates`
88+
89+
7390
Files Rendering
7491
====================
7592

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ docker-compose
8888
input
8989
features
9090
jinja2_functions_filters
91+
certificates
9192
examples
9293
modules
9394
contributing

ecs-files-input.json

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -320,23 +320,23 @@
320320
"countryName": {
321321
"type": "string",
322322
"pattern": "^[A-Z]+$",
323-
"default": "AW"
323+
"default": "ZZ"
324324
},
325325
"localityName": {
326326
"type": "string",
327-
"default": "AWS"
327+
"default": "Anywhere"
328328
},
329329
"stateOrProvinceName": {
330330
"type": "string",
331-
"default": "AWS"
331+
"default": "Shire"
332332
},
333333
"organizationName": {
334334
"type": "string",
335-
"default": "AWS"
335+
"default": "NoOne"
336336
},
337337
"organizationUnitName": {
338338
"type": "string",
339-
"default": "AWS"
339+
"default": "Automation"
340340
},
341341
"validityEndInSeconds": {
342342
"type": "number",
@@ -358,6 +358,25 @@
358358
"type": "string",
359359
"description": "UNIX user or UID owner of the file. Default to root(0)",
360360
"default": "root"
361+
},
362+
"jksConfig": {
363+
"description": "Configuration that will allow to transform the certificate into a JKS for java applications",
364+
"type": "object",
365+
"additionalProperties": false,
366+
"required": [
367+
"fileName",
368+
"passphrase"
369+
],
370+
"properties": {
371+
"fileName": {
372+
"type": "string",
373+
"description": "Name of the JKS file to create"
374+
},
375+
"passphrase": {
376+
"type": "string",
377+
"description": "The passphrase to use to secure the jks and certificate"
378+
}
379+
}
361380
}
362381
}
363382
},

ecs_files_composer/certificates_mgmt.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from os import path
77
from typing import Any
88

9+
import jks as pyjks
910
from OpenSSL import crypto
1011

1112
from ecs_files_composer.files_mgmt import File
@@ -27,6 +28,7 @@ def __init__(self, **data: Any):
2728
self.key_file = None
2829
self.cert_file_path = None
2930
self.key_file_path = None
31+
self.keystore = None
3032

3133
def init_cert_paths(self):
3234
self.cert_file_path = path.abspath(f"{self.dir_path}/{self.cert_file_name}")
@@ -95,6 +97,22 @@ def set_cert_files(self):
9597
}
9698
)
9799

100+
def generate_jks(self):
101+
"""
102+
Creates a JKS from the private key and certificate
103+
:return:
104+
"""
105+
jks_path = path.abspath(f"{self.dir_path}/{self.jks_config.file_name}")
106+
pkey = pyjks.jks.PrivateKeyEntry.new(
107+
self.key_file_name,
108+
certs=[crypto.dump_certificate(crypto.FILETYPE_ASN1, self.cert)],
109+
key=self.key_content,
110+
key_format="rsa_raw",
111+
)
112+
pkey.encrypt(self.jks_config.passphrase)
113+
self.keystore = pyjks.KeyStore.new("jks", [pkey])
114+
self.keystore.save(jks_path, self.jks_config.passphrase)
115+
98116

99117
def process_x509_certs(job):
100118
"""
@@ -111,6 +129,10 @@ def process_x509_certs(job):
111129
cert_obj.dir_path = cert_path
112130
cert_obj.init_cert_paths()
113131
cert_obj.set_cert_files()
132+
if cert_obj.jks_config:
133+
cert_obj.generate_jks()
114134
job.certificates.x509[cert_path] = cert_obj
135+
if not job.files:
136+
job.files = {}
115137
job.files[cert_obj.cert_file.path] = cert_obj.cert_file
116138
job.files[cert_obj.key_file_path] = cert_obj.key_file

ecs_files_composer/input.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# generated by datamodel-codegen:
22
# filename: ecs-files-input.json
3-
# timestamp: 2022-11-23T17:19:16+00:00
3+
# timestamp: 2023-02-22T16:56:14+00:00
44

55
from __future__ import annotations
66

@@ -87,6 +87,18 @@ class CommandsDef(BaseModel):
8787
__root__: List[str] = Field(..., description="List of commands to run")
8888

8989

90+
class JksConfig(BaseModel):
91+
class Config:
92+
extra = Extra.forbid
93+
94+
file_name: str = Field(
95+
..., alias="fileName", description="Name of the JKS file to create"
96+
)
97+
passphrase: str = Field(
98+
..., description="The passphrase to use to secure the jks and certificate"
99+
)
100+
101+
90102
class X509CertDef(BaseModel):
91103
class Config:
92104
extra = Extra.allow
@@ -100,11 +112,13 @@ class Config:
100112
regex=r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]{0,61}[A-Za-z0-9])\Z"
101113
)
102114
] = Field(None, alias="commonName")
103-
country_name: Optional[str] = Field("AW", alias="countryName", regex="^[A-Z]+$")
104-
locality_name: Optional[str] = Field("AWS", alias="localityName")
105-
state_or_province_name: Optional[str] = Field("AWS", alias="stateOrProvinceName")
106-
organization_name: Optional[str] = Field("AWS", alias="organizationName")
107-
organization_unit_name: Optional[str] = Field("AWS", alias="organizationUnitName")
115+
country_name: Optional[str] = Field("ZZ", alias="countryName", regex="^[A-Z]+$")
116+
locality_name: Optional[str] = Field("Anywhere", alias="localityName")
117+
state_or_province_name: Optional[str] = Field("Shire", alias="stateOrProvinceName")
118+
organization_name: Optional[str] = Field("NoOne", alias="organizationName")
119+
organization_unit_name: Optional[str] = Field(
120+
"Automation", alias="organizationUnitName"
121+
)
108122
validity_end_in_seconds: Optional[float] = Field(
109123
8035200,
110124
alias="validityEndInSeconds",
@@ -119,6 +133,11 @@ class Config:
119133
owner: Optional[str] = Field(
120134
"root", description="UNIX user or UID owner of the file. Default to root(0)"
121135
)
136+
jks_config: Optional[JksConfig] = Field(
137+
None,
138+
alias="jksConfig",
139+
description="Configuration that will allow to transform the certificate into a JKS for java applications",
140+
)
122141

123142

124143
class CertbotAwsStoreCertificate(BaseModel):

0 commit comments

Comments
 (0)