fix: restrict key.pem file permissions to 0600 (owner-only)
All private key writes now use writeAtomicRestricted which sets POSIX owner-read/write permissions after writing. Gracefully skips on non-POSIX filesystems (Windows dev). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -113,7 +113,7 @@ public class DockerCertificateManager implements CertificateManager {
|
|||||||
Files.createDirectories(stagedDir);
|
Files.createDirectories(stagedDir);
|
||||||
|
|
||||||
writeAtomic(stagedDir.resolve("cert.pem"), certPem);
|
writeAtomic(stagedDir.resolve("cert.pem"), certPem);
|
||||||
writeAtomic(stagedDir.resolve("key.pem"), decryptedKeyPem);
|
writeAtomicRestricted(stagedDir.resolve("key.pem"), decryptedKeyPem);
|
||||||
if (caBundlePem != null && caBundlePem.length > 0) {
|
if (caBundlePem != null && caBundlePem.length > 0) {
|
||||||
writeAtomic(stagedDir.resolve("ca.pem"), caBundlePem);
|
writeAtomic(stagedDir.resolve("ca.pem"), caBundlePem);
|
||||||
} else {
|
} else {
|
||||||
@@ -153,7 +153,7 @@ public class DockerCertificateManager implements CertificateManager {
|
|||||||
|
|
||||||
// Move staged -> active (atomic swap via .wip)
|
// Move staged -> active (atomic swap via .wip)
|
||||||
writeAtomic(certsDir.resolve("cert.pem"), Files.readAllBytes(stagedDir.resolve("cert.pem")));
|
writeAtomic(certsDir.resolve("cert.pem"), Files.readAllBytes(stagedDir.resolve("cert.pem")));
|
||||||
writeAtomic(certsDir.resolve("key.pem"), Files.readAllBytes(stagedDir.resolve("key.pem")));
|
writeAtomicRestricted(certsDir.resolve("key.pem"), Files.readAllBytes(stagedDir.resolve("key.pem")));
|
||||||
if (Files.exists(stagedDir.resolve("ca.pem"))) {
|
if (Files.exists(stagedDir.resolve("ca.pem"))) {
|
||||||
writeAtomic(certsDir.resolve("ca.pem"), Files.readAllBytes(stagedDir.resolve("ca.pem")));
|
writeAtomic(certsDir.resolve("ca.pem"), Files.readAllBytes(stagedDir.resolve("ca.pem")));
|
||||||
}
|
}
|
||||||
@@ -187,7 +187,7 @@ public class DockerCertificateManager implements CertificateManager {
|
|||||||
|
|
||||||
// Prev -> active
|
// Prev -> active
|
||||||
writeAtomic(certsDir.resolve("cert.pem"), Files.readAllBytes(prevDir.resolve("cert.pem")));
|
writeAtomic(certsDir.resolve("cert.pem"), Files.readAllBytes(prevDir.resolve("cert.pem")));
|
||||||
writeAtomic(certsDir.resolve("key.pem"), Files.readAllBytes(prevDir.resolve("key.pem")));
|
writeAtomicRestricted(certsDir.resolve("key.pem"), Files.readAllBytes(prevDir.resolve("key.pem")));
|
||||||
if (Files.exists(prevDir.resolve("ca.pem"))) {
|
if (Files.exists(prevDir.resolve("ca.pem"))) {
|
||||||
writeAtomic(certsDir.resolve("ca.pem"), Files.readAllBytes(prevDir.resolve("ca.pem")));
|
writeAtomic(certsDir.resolve("ca.pem"), Files.readAllBytes(prevDir.resolve("ca.pem")));
|
||||||
} else {
|
} else {
|
||||||
@@ -355,6 +355,23 @@ public class DockerCertificateManager implements CertificateManager {
|
|||||||
Files.move(wip, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
Files.move(wip, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Write with owner-only permissions (0600) for private key files. */
|
||||||
|
private void writeAtomicRestricted(Path target, byte[] data) throws IOException {
|
||||||
|
writeAtomic(target, data);
|
||||||
|
try {
|
||||||
|
var posix = Files.getFileAttributeView(target, java.nio.file.attribute.PosixFileAttributeView.class);
|
||||||
|
if (posix != null) {
|
||||||
|
posix.setPermissions(java.util.Set.of(
|
||||||
|
java.nio.file.attribute.PosixFilePermission.OWNER_READ,
|
||||||
|
java.nio.file.attribute.PosixFilePermission.OWNER_WRITE
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
// Non-POSIX filesystem (e.g., Windows) — skip
|
||||||
|
log.debug("Cannot set POSIX permissions on {}: {}", target, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void moveFile(Path source, Path target) throws IOException {
|
private void moveFile(Path source, Path target) throws IOException {
|
||||||
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user