mirror of https://github.com/apache/jclouds.git
Properly set the permissions in the ~/.ssh folder
When writing the ~/.ssh/authorized_keys file in a script that is being run as sudo, the file is created with the root owner, instead of the user defined by the node credentials. File ownership should be enforced to make sure the right owner is alwaays set.
This commit is contained in:
parent
04c2394a10
commit
179ed3b2f6
|
@ -47,7 +47,6 @@ import org.jclouds.compute.extensions.ImageExtension;
|
|||
import org.jclouds.compute.extensions.SecurityGroupExtension;
|
||||
import org.jclouds.compute.functions.CreateSshClientOncePortIsListeningOnNode;
|
||||
import org.jclouds.compute.functions.DefaultCredentialsFromImageOrOverridingCredentials;
|
||||
import org.jclouds.compute.functions.TemplateOptionsToStatement;
|
||||
import org.jclouds.compute.options.RunScriptOptions;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
|
@ -89,8 +88,6 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
|
|||
install(new ComputeServiceTimeoutsModule());
|
||||
bind(new TypeLiteral<Function<NodeMetadata, SshClient>>() {
|
||||
}).to(CreateSshClientOncePortIsListeningOnNode.class);
|
||||
bind(new TypeLiteral<Function<TemplateOptions, Statement>>() {
|
||||
}).to(TemplateOptionsToStatement.class);
|
||||
bind(LoginCredentials.class).annotatedWith(Names.named("image")).toProvider(
|
||||
GetLoginForProviderFromPropertiesAndStoreCredentialsOrReturnNull.class);
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
@ -29,17 +30,20 @@ import org.jclouds.scriptbuilder.domain.StatementList;
|
|||
import org.jclouds.scriptbuilder.statements.ssh.AuthorizeRSAPublicKeys;
|
||||
import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
@Singleton
|
||||
public class TemplateOptionsToStatement implements Function<TemplateOptions, Statement> {
|
||||
public class InstallKeysAndRunScript implements NodeAndTemplateOptionsToStatement {
|
||||
|
||||
@Override
|
||||
public Statement apply(TemplateOptions options) {
|
||||
public Statement apply(NodeMetadata node, TemplateOptions options) {
|
||||
String user = options.getLoginUser();
|
||||
if (user == null && node.getCredentials() != null) {
|
||||
user = node.getCredentials().getUser();
|
||||
}
|
||||
List<Statement> bootstrap = newArrayList();
|
||||
if (options.getPublicKey() != null)
|
||||
bootstrap.add(new AuthorizeRSAPublicKeys(ImmutableSet.of(options.getPublicKey())));
|
||||
bootstrap.add(new AuthorizeRSAPublicKeys(ImmutableSet.of(options.getPublicKey()), user));
|
||||
if (options.getRunScript() != null)
|
||||
bootstrap.add(options.getRunScript());
|
||||
if (options.getPrivateKey() != null)
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.compute.functions;
|
||||
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
|
||||
/**
|
||||
* Returns the statement to be executed on the node.
|
||||
*/
|
||||
@ImplementedBy(InstallKeysAndRunScript.class)
|
||||
public interface NodeAndTemplateOptionsToStatement {
|
||||
|
||||
/**
|
||||
* Returns the script that has to be executed in the given node.
|
||||
*
|
||||
* @return The script to be executed or <code>null</code> if no script needs
|
||||
* to be run.
|
||||
*/
|
||||
@Nullable
|
||||
Statement apply(NodeMetadata node, TemplateOptions options);
|
||||
}
|
|
@ -14,29 +14,31 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.digitalocean2.compute.functions;
|
||||
package org.jclouds.compute.functions;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.compute.functions.TemplateOptionsToStatement;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.scriptbuilder.InitScript;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
||||
import org.jclouds.scriptbuilder.statements.ssh.InstallRSAPrivateKey;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Convert the template options into a statement, but ignoring the public key.
|
||||
* Convert the node and template options into a statement, but ignoring the
|
||||
* public key.
|
||||
* <p>
|
||||
* The {@link org.jclouds.DigitalOcean2ComputeServiceAdapter.compute.strategy.DigitalOceanComputeServiceAdapter} already takes care of
|
||||
* installing it using the {@link org.jclouds.digitalocean.features.KeyPairApi}.
|
||||
* Providers that can install the public key using their API should bind this
|
||||
* strategy to avoid an unnecessary SSH connection to manually upload it.
|
||||
*/
|
||||
@Singleton
|
||||
public class TemplateOptionsToStatementWithoutPublicKey extends TemplateOptionsToStatement {
|
||||
public class NodeAndTemplateOptionsToStatementWithoutPublicKey implements NodeAndTemplateOptionsToStatement {
|
||||
|
||||
@Override
|
||||
public Statement apply(TemplateOptions options) {
|
||||
public Statement apply(NodeMetadata node, TemplateOptions options) {
|
||||
ImmutableList.Builder<Statement> builder = ImmutableList.builder();
|
||||
if (options.getRunScript() != null) {
|
||||
builder.add(options.getRunScript());
|
||||
|
@ -55,5 +57,4 @@ public class TemplateOptionsToStatementWithoutPublicKey extends TemplateOptionsT
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.jclouds.compute.callables.RunScriptOnNode;
|
|||
import org.jclouds.compute.config.CustomizationResponse;
|
||||
import org.jclouds.compute.domain.ExecResponse;
|
||||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||
import org.jclouds.compute.util.OpenSocketFinder;
|
||||
|
@ -66,7 +67,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
|||
private final OpenSocketFinder openSocketFinder;
|
||||
|
||||
@Nullable
|
||||
private final Statement statement;
|
||||
private final NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement;
|
||||
private final TemplateOptions options;
|
||||
private AtomicReference<NodeMetadata> node;
|
||||
private final Set<NodeMetadata> goodNodes;
|
||||
|
@ -78,13 +79,13 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
|||
@AssistedInject
|
||||
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
|
||||
@Named(TIMEOUT_NODE_RUNNING) Function<AtomicReference<NodeMetadata>, AtomicReference<NodeMetadata>> pollNodeRunning,
|
||||
OpenSocketFinder openSocketFinder, Function<TemplateOptions, Statement> templateOptionsToStatement,
|
||||
OpenSocketFinder openSocketFinder, NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
|
||||
@Assisted AtomicReference<NodeMetadata> node, @Assisted Set<NodeMetadata> goodNodes,
|
||||
@Assisted Map<NodeMetadata, Exception> badNodes,
|
||||
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||
this.statement = checkNotNull(templateOptionsToStatement, "templateOptionsToStatement").apply(
|
||||
checkNotNull(options, "options"));
|
||||
this.nodeAndTemplateOptionsToStatement = checkNotNull(nodeAndTemplateOptionsToStatement,
|
||||
"nodeAndTemplateOptionsToStatement");
|
||||
this.pollNodeRunning = checkNotNull(pollNodeRunning, "pollNodeRunning");
|
||||
this.initScriptRunnerFactory = checkNotNull(initScriptRunnerFactory, "initScriptRunnerFactory");
|
||||
this.openSocketFinder = checkNotNull(openSocketFinder, "openSocketFinder");
|
||||
|
@ -99,11 +100,11 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
|||
public CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(
|
||||
@Named(TIMEOUT_NODE_RUNNING) Function<AtomicReference<NodeMetadata>, AtomicReference<NodeMetadata>> pollNodeRunning,
|
||||
GetNodeMetadataStrategy getNode, OpenSocketFinder openSocketFinder,
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement,
|
||||
NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement,
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, @Assisted TemplateOptions options,
|
||||
@Assisted Set<NodeMetadata> goodNodes, @Assisted Map<NodeMetadata, Exception> badNodes,
|
||||
@Assisted Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
|
||||
this(pollNodeRunning, openSocketFinder, templateOptionsToStatement, initScriptRunnerFactory, options,
|
||||
this(pollNodeRunning, openSocketFinder, nodeAndTemplateOptionsToStatement, initScriptRunnerFactory, options,
|
||||
new AtomicReference<NodeMetadata>(null), goodNodes, badNodes, customizationResponses);
|
||||
}
|
||||
|
||||
|
@ -115,6 +116,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap implements Cal
|
|||
try {
|
||||
if (options.shouldBlockUntilRunning()) {
|
||||
pollNodeRunning.apply(node);
|
||||
Statement statement = nodeAndTemplateOptionsToStatement.apply(node.get(), options);
|
||||
if (statement != null) {
|
||||
RunScriptOnNode runner = initScriptRunnerFactory.create(node.get(), statement, options, badNodes).call();
|
||||
if (runner != null) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.digitalocean2.compute.functions;
|
||||
package org.jclouds.compute.functions;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
@ -31,18 +31,17 @@ import org.jclouds.ssh.SshKeys;
|
|||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link TemplateOptionsToStatementWithoutPublicKey} class.
|
||||
* Unit tests for the {@link NodeAndTemplateOptionsToStatementWithoutPublicKey} class.
|
||||
*/
|
||||
@Test(groups = "unit", testName = "TemplateOptionsToStatementWithoutPublicKeyTest")
|
||||
public class TemplateOptionsToStatementWithoutPublicKeyTest {
|
||||
@Test(groups = "unit", testName = "NodeAndTemplateOptionsToStatementWithoutPublicKeyTest")
|
||||
public class NodeAndTemplateOptionsToStatementWithoutPublicKeyTest {
|
||||
|
||||
@Test
|
||||
public void testPublicKeyDoesNotGenerateAuthorizePublicKeyStatementIfOnlyPublicKeyOptionsConfigured() {
|
||||
Map<String, String> keys = SshKeys.generate();
|
||||
TemplateOptions options = TemplateOptions.Builder.authorizePublicKey(keys.get("public"));
|
||||
|
||||
TemplateOptionsToStatementWithoutPublicKey function = new TemplateOptionsToStatementWithoutPublicKey();
|
||||
assertNull(function.apply(options));
|
||||
NodeAndTemplateOptionsToStatementWithoutPublicKey function = new NodeAndTemplateOptionsToStatementWithoutPublicKey();
|
||||
assertNull(function.apply(null, options));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -50,8 +49,8 @@ public class TemplateOptionsToStatementWithoutPublicKeyTest {
|
|||
Map<String, String> keys = SshKeys.generate();
|
||||
TemplateOptions options = TemplateOptions.Builder.authorizePublicKey(keys.get("public")).runScript("uptime");
|
||||
|
||||
TemplateOptionsToStatementWithoutPublicKey function = new TemplateOptionsToStatementWithoutPublicKey();
|
||||
Statement statement = function.apply(options);
|
||||
NodeAndTemplateOptionsToStatementWithoutPublicKey function = new NodeAndTemplateOptionsToStatementWithoutPublicKey();
|
||||
Statement statement = function.apply(null, options);
|
||||
|
||||
assertEquals(statement.render(OsFamily.UNIX), "uptime\n");
|
||||
}
|
||||
|
@ -62,8 +61,8 @@ public class TemplateOptionsToStatementWithoutPublicKeyTest {
|
|||
TemplateOptions options = TemplateOptions.Builder.authorizePublicKey(keys.get("public"))
|
||||
.installPrivateKey(keys.get("private")).runScript("uptime");
|
||||
|
||||
TemplateOptionsToStatementWithoutPublicKey function = new TemplateOptionsToStatementWithoutPublicKey();
|
||||
Statement statement = function.apply(options);
|
||||
NodeAndTemplateOptionsToStatementWithoutPublicKey function = new NodeAndTemplateOptionsToStatementWithoutPublicKey();
|
||||
Statement statement = function.apply(null, options);
|
||||
|
||||
assertTrue(statement instanceof StatementList);
|
||||
StatementList statements = (StatementList) statement;
|
|
@ -32,7 +32,8 @@ import org.jclouds.compute.config.CustomizationResponse;
|
|||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.NodeMetadata.Status;
|
||||
import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||
import org.jclouds.compute.functions.TemplateOptionsToStatement;
|
||||
import org.jclouds.compute.functions.InstallKeysAndRunScript;
|
||||
import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.util.OpenSocketFinder;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
|
@ -53,7 +54,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
|||
public void testBreakOnIllegalStateExceptionDuringPollNode() {
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
|
||||
OpenSocketFinder openSocketFinder = createMock(OpenSocketFinder.class);
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
|
||||
NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement = new InstallKeysAndRunScript();
|
||||
@SuppressWarnings("unused")
|
||||
Statement statement = null;
|
||||
TemplateOptions options = new TemplateOptions();
|
||||
|
@ -79,7 +80,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
|||
// run
|
||||
AtomicReference<NodeMetadata> atomicNode = Atomics.newReference(pendingNode);
|
||||
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(pollNodeRunning, openSocketFinder,
|
||||
templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
|
||||
nodeAndTemplateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
|
||||
customizationResponses).apply(atomicNode);
|
||||
|
||||
assertEquals(goodNodes.size(), 0);
|
||||
|
@ -95,7 +96,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
|||
int portTimeoutSecs = 2;
|
||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory = createMock(InitializeRunScriptOnNodeOrPlaceInBadMap.Factory.class);
|
||||
OpenSocketFinder openSocketFinder = createMock(OpenSocketFinder.class);
|
||||
Function<TemplateOptions, Statement> templateOptionsToStatement = new TemplateOptionsToStatement();
|
||||
NodeAndTemplateOptionsToStatement nodeAndTemplateOptionsToStatement = new InstallKeysAndRunScript();
|
||||
TemplateOptions options = new TemplateOptions().blockOnPort(22, portTimeoutSecs);
|
||||
Set<NodeMetadata> goodNodes = Sets.newLinkedHashSet();
|
||||
Map<NodeMetadata, Exception> badNodes = Maps.newLinkedHashMap();
|
||||
|
@ -124,7 +125,7 @@ public class CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapTest {
|
|||
// run
|
||||
AtomicReference<NodeMetadata> atomicNode = Atomics.newReference(pendingNode);
|
||||
new CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap(pollNodeRunning, openSocketFinder,
|
||||
templateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
|
||||
nodeAndTemplateOptionsToStatement, initScriptRunnerFactory, options, atomicNode, goodNodes, badNodes,
|
||||
customizationResponses).apply(atomicNode);
|
||||
|
||||
assertEquals(goodNodes.size(), 0);
|
||||
|
|
|
@ -219,6 +219,7 @@ END_OF_JCLOUDS_SCRIPT
|
|||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
|
@ -219,6 +219,7 @@ END_OF_JCLOUDS_SCRIPT
|
|||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/web/.ssh/authorized_keys
|
||||
chown -R web /home/users/web/.ssh
|
||||
chown -R web /home/users/web
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
|
@ -100,6 +100,7 @@ END_OF_JCLOUDS_SCRIPT
|
|||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /over/ridden/foo/.ssh/authorized_keys
|
||||
chown -R foo /over/ridden/foo/.ssh
|
||||
chown -R foo /over/ridden/foo
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
|
@ -32,7 +32,8 @@ import org.jclouds.compute.domain.Image;
|
|||
import org.jclouds.compute.domain.NodeMetadata;
|
||||
import org.jclouds.compute.domain.NodeMetadata.Status;
|
||||
import org.jclouds.compute.extensions.ImageExtension;
|
||||
import org.jclouds.compute.functions.TemplateOptionsToStatement;
|
||||
import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatement;
|
||||
import org.jclouds.compute.functions.NodeAndTemplateOptionsToStatementWithoutPublicKey;
|
||||
import org.jclouds.compute.options.TemplateOptions;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants.PollPeriod;
|
||||
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
|
||||
|
@ -45,7 +46,6 @@ import org.jclouds.digitalocean2.compute.functions.DropletToNodeMetadata;
|
|||
import org.jclouds.digitalocean2.compute.functions.ImageInRegionToImage;
|
||||
import org.jclouds.digitalocean2.compute.functions.RegionToLocation;
|
||||
import org.jclouds.digitalocean2.compute.functions.SizeToHardware;
|
||||
import org.jclouds.digitalocean2.compute.functions.TemplateOptionsToStatementWithoutPublicKey;
|
||||
import org.jclouds.digitalocean2.compute.internal.ImageInRegion;
|
||||
import org.jclouds.digitalocean2.compute.options.DigitalOcean2TemplateOptions;
|
||||
import org.jclouds.digitalocean2.compute.strategy.CreateKeyPairsThenCreateNodes;
|
||||
|
@ -91,7 +91,7 @@ public class DigitalOcean2ComputeServiceContextModule extends
|
|||
|
||||
bind(CreateNodesInGroupThenAddToSet.class).to(CreateKeyPairsThenCreateNodes.class);
|
||||
bind(TemplateOptions.class).to(DigitalOcean2TemplateOptions.class);
|
||||
bind(TemplateOptionsToStatement.class).to(TemplateOptionsToStatementWithoutPublicKey.class);
|
||||
bind(NodeAndTemplateOptionsToStatement.class).to(NodeAndTemplateOptionsToStatementWithoutPublicKey.class);
|
||||
|
||||
bind(new TypeLiteral<ImageExtension>() {
|
||||
}).to(DigitalOcean2ImageExtension.class);
|
||||
|
|
|
@ -231,7 +231,7 @@ public class UserAdd implements Statement {
|
|||
if (!authorizeRSAPublicKeys.isEmpty() || installRSAPrivateKey != null) {
|
||||
String sshDir = homeDir + "{fs}.ssh";
|
||||
if (!authorizeRSAPublicKeys.isEmpty())
|
||||
statements.add(new AuthorizeRSAPublicKeys(sshDir, authorizeRSAPublicKeys));
|
||||
statements.add(new AuthorizeRSAPublicKeys(sshDir, authorizeRSAPublicKeys, login));
|
||||
if (installRSAPrivateKey != null)
|
||||
statements.add(new InstallRSAPrivateKey(sshDir, installRSAPrivateKey));
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import static org.jclouds.scriptbuilder.domain.Statements.exec;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.scriptbuilder.domain.OsFamily;
|
||||
import org.jclouds.scriptbuilder.domain.Statement;
|
||||
import org.jclouds.scriptbuilder.domain.StatementList;
|
||||
|
@ -34,14 +35,20 @@ import com.google.common.collect.ImmutableList.Builder;
|
|||
public class AuthorizeRSAPublicKeys implements Statement {
|
||||
private final String sshDir;
|
||||
private final List<String> publicKeys;
|
||||
|
||||
private final String owner;
|
||||
|
||||
public AuthorizeRSAPublicKeys(Iterable<String> publicKeys) {
|
||||
this("~/.ssh", publicKeys);
|
||||
this("~/.ssh", publicKeys, null);
|
||||
}
|
||||
|
||||
public AuthorizeRSAPublicKeys(Iterable<String> publicKeys, @Nullable String owner) {
|
||||
this("~/.ssh", publicKeys, owner);
|
||||
}
|
||||
|
||||
public AuthorizeRSAPublicKeys(String sshDir, Iterable<String> publicKeys) {
|
||||
public AuthorizeRSAPublicKeys(String sshDir, Iterable<String> publicKeys, @Nullable String owner) {
|
||||
this.sshDir = checkNotNull(sshDir, "sshDir");
|
||||
this.publicKeys = ImmutableList.copyOf(checkNotNull(publicKeys, "publicKeys"));
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,6 +66,9 @@ public class AuthorizeRSAPublicKeys implements Statement {
|
|||
String authorizedKeys = sshDir + "{fs}authorized_keys";
|
||||
statements.add(appendFile(authorizedKeys, Splitter.on('\n').split(Joiner.on("\n\n").join(publicKeys))));
|
||||
statements.add(exec("chmod 600 " + authorizedKeys));
|
||||
if (owner != null) {
|
||||
statements.add(exec(String.format("chown -R %s %s", owner, sshDir)));
|
||||
}
|
||||
return new StatementList(statements.build()).render(family);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ public class UserAddTest {
|
|||
public void testWithSshAuthorizedKeyUNIX() {
|
||||
assertEquals(
|
||||
UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX),
|
||||
"mkdir -p /home/users\nchmod 0755 /home/users\nuseradd -c me -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n");
|
||||
"mkdir -p /home/users\nchmod 0755 /home/users\nuseradd -c me -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me/.ssh\nchown -R me /home/users/me\n");
|
||||
}
|
||||
|
||||
public void testWithSshInstalledKeyUNIX() {
|
||||
|
|
|
@ -27,6 +27,17 @@ import com.google.common.collect.ImmutableSet;
|
|||
public class AuthorizeRSAPublicKeyTest {
|
||||
|
||||
public void testAuthorizeRSAPublicKeyUNIXCurrentUser() {
|
||||
assertEquals(
|
||||
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB"), "jclouds").render(OsFamily.UNIX),
|
||||
"mkdir -p ~/.ssh\n" +
|
||||
"cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
|
||||
"\tssh-dss AAAAB\n" +
|
||||
"END_OF_JCLOUDS_FILE\n" +
|
||||
"chmod 600 ~/.ssh/authorized_keys\n" +
|
||||
"chown -R jclouds ~/.ssh\n");
|
||||
}
|
||||
|
||||
public void testAuthorizeRSAPublicKeyUNIXNoOwner() {
|
||||
assertEquals(
|
||||
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
|
||||
"mkdir -p ~/.ssh\n" +
|
||||
|
@ -38,29 +49,31 @@ public class AuthorizeRSAPublicKeyTest {
|
|||
|
||||
public void testAuthorizeRSAPublicKeyUNIXCurrentUserWith2Keys() {
|
||||
assertEquals(
|
||||
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD")).render(OsFamily.UNIX),
|
||||
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"), "jclouds").render(OsFamily.UNIX),
|
||||
"mkdir -p ~/.ssh\n" +
|
||||
"cat >> ~/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
|
||||
"\tssh-dss AAAAB\n" +
|
||||
"\t\n" +
|
||||
"\tssh-dss CCCCD\n" +
|
||||
"END_OF_JCLOUDS_FILE\n" +
|
||||
"chmod 600 ~/.ssh/authorized_keys\n");
|
||||
"chmod 600 ~/.ssh/authorized_keys\n" +
|
||||
"chown -R jclouds ~/.ssh\n");
|
||||
}
|
||||
|
||||
public void testAuthorizeRSAPublicKeyUNIXSpecifiedDir() {
|
||||
assertEquals(
|
||||
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.UNIX),
|
||||
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB"), "jclouds").render(OsFamily.UNIX),
|
||||
"mkdir -p /home/me/.ssh\n" +
|
||||
"cat >> /home/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
|
||||
"\tssh-dss AAAAB\n" +
|
||||
"END_OF_JCLOUDS_FILE\n" +
|
||||
"chmod 600 /home/me/.ssh/authorized_keys\n");
|
||||
"chmod 600 /home/me/.ssh/authorized_keys\n" +
|
||||
"chown -R jclouds /home/me/.ssh\n");
|
||||
}
|
||||
|
||||
public void testAuthorizeRSAPublicKeyUNIXSpecifiedDirWith2Keys() {
|
||||
assertEquals(
|
||||
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"))
|
||||
new AuthorizeRSAPublicKeys("/home/me/.ssh", ImmutableSet.of("ssh-dss AAAAB", "ssh-dss CCCCD"), "jclouds")
|
||||
.render(OsFamily.UNIX),
|
||||
"mkdir -p /home/me/.ssh\n" +
|
||||
"cat >> /home/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n" +
|
||||
|
@ -68,11 +81,12 @@ public class AuthorizeRSAPublicKeyTest {
|
|||
"\t\n" +
|
||||
"\tssh-dss CCCCD\n" +
|
||||
"END_OF_JCLOUDS_FILE\n" +
|
||||
"chmod 600 /home/me/.ssh/authorized_keys\n");
|
||||
"chmod 600 /home/me/.ssh/authorized_keys\n" +
|
||||
"chown -R jclouds /home/me/.ssh\n");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = UnsupportedOperationException.class)
|
||||
public void testAuthorizeRSAPublicKeyWINDOWS() {
|
||||
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB")).render(OsFamily.WINDOWS);
|
||||
new AuthorizeRSAPublicKeys(ImmutableSet.of("ssh-dss AAAAB"), "jclouds").render(OsFamily.WINDOWS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<'END_OF_FILE'
|
|||
publicKey
|
||||
END_OF_FILE
|
||||
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
|
@ -14,6 +14,7 @@ cat >> /over/ridden/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
|
|||
fooPublicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /over/ridden/foo/.ssh/authorized_keys
|
||||
chown -R foo /over/ridden/foo/.ssh
|
||||
chown -R foo /over/ridden/foo
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
|
@ -14,6 +14,7 @@ cat >> /over/ridden/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'
|
|||
fooPublicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /over/ridden/foo/.ssh/authorized_keys
|
||||
chown -R foo /over/ridden/foo/.ssh
|
||||
chown -R foo /over/ridden/foo
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
|
@ -6,6 +6,7 @@ cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_
|
|||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
|
||||
mkdir -p /home/users/defaultAdminUsername/.ssh
|
||||
rm /home/users/defaultAdminUsername/.ssh/id_rsa
|
||||
cat >> /home/users/defaultAdminUsername/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'
|
||||
|
|
|
@ -14,6 +14,7 @@ cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_
|
|||
publicKey
|
||||
END_OF_JCLOUDS_FILE
|
||||
chmod 600 /home/users/defaultAdminUsername/.ssh/authorized_keys
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername/.ssh
|
||||
chown -R defaultAdminUsername /home/users/defaultAdminUsername
|
||||
exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no
|
||||
PermitRootLogin no
|
||||
|
|
Loading…
Reference in New Issue