C# private key로 SSH 접속 후 리모트 내의 MySQL에 접속해서 DB 조작
하고 싶은 것
- C#으로 콘솔 응용 어플을 작성
- 외부에 있는 Linux 서버(VPS)에 private key로 SSH 접속해서 이것 저것 만지고 싶다
- 리모트 측의 MySQL(해당 서버 입장에서 보면 Localhost)에 접속해서 DB를 조작하고 싶다
전제 조건
SSH의 private key는 빌드한 폴더에 격납한다.
ex) \bin\Debug\openssh.key 또는 \bin\Release\openssh.key
※기본의 id_rsa(private key)파일을 카피해서 openssh.key로 이름을 변경하였다.
필요한 패키지
SSH.NET
- https://www.nuget.org/packages/SSH.NET/
MySql.Data
- https://www.nuget.org/packages/MySql.Data/
MySql.Data의 버젼은 각자의 상황에 맞춘다.
(하기 샘플에서 검증할때 쓴 MySql.Data의 버젼은 6.9.11.0)
샘플
using Renci.SshNet;
using MySql.Data.MySqlClient;
using System.Data;
public const string LocalHostAddress = "localhost";
// 미사용 포트라면 뭐든 가능(개발단말/운용단말 기준의 빈 포트 번호)
public const uint LocalHostPort = 13306;
// ip 또는 호스트 이름
public const string RelayHostAddress = "dev.test";
// ssh의 포트 번호(RelayHostAddress(운용단말)의 ssh에 어느 port 번호가 설정되어 있는가에 따라 달라진다(22이나 10022가 일반적?))
public const int RelayHostPort = 22;
// ssh에 접속할 유저 이름
public const string SshUser = "sshuser";
// private key의 설정. RelayHostAddress(운용단말)에 SshUser로 유저 등록이 되어 있고, 공개키가 등록되어 있는것이 전제
public const string SshPrivateKeyFileName = "openssh.key";
// SshPrivateKeyFileName(ssh키)를 만들 시에 지정한 패스워드
public const string SshPassword = "pass";
// DB의 호스트 어드레스. 리모트 접속처인 RelayHostAddress(운용단말)에 존재하는 DB이므로 "127.0.0.1"를 설정
public const string DbHostAddress = "127.0.0.1";
// MySQL의 포트 번호
public const uint DbHostPort = 3306;
public const string MySqlUser = "root";
// 패스워드 미지정의 경우엔 ""(공백)
public const string MySqlPassword = "";
// db스키마 이름
public const string DbName = "test";
// 검증용으로 접속할 테이블 이름
public const string TableName = "tbl_test";
public void AccessSshAndMySql()
{
// Setup Credentials and Server Information
// Key Based Authentication (using keys in OpenSSH Format)
var ConnNfo = new ConnectionInfo(RelayHostAddress, RelayHostPort, SshUser,
new AuthenticationMethod[]{
new PrivateKeyAuthenticationMethod(SshUser,new PrivateKeyFile[]{
new PrivateKeyFile(SshPrivateKeyFileName, SshPassword)
}),
}
);
using (var client = new SshClient(ConnNfo))
{
client.Connect();
try
{
if (!client.IsConnected)
{
Console.WriteLine("[NG] SSH Connection failed!!");
}
// SSH를 경유해서 개발단말(운용단말에 접속하러 갈 PC)의 미사용 포트 번호를 이용해서 운용단말에 있는 MySQL에 접속 가능하도록 한다.
using (var forwardedPortLocal = new ForwardedPortLocal(LocalHostAddress, LocalHostPort, DbHostAddress, DbHostPort))
{
client.AddForwardedPort(forwardedPortLocal);
try
{
forwardedPortLocal.Start();
if (!forwardedPortLocal.IsStarted)
{
Console.WriteLine("[NG] forwardedPortLocal Connection failed!!");
}
// MySQL Start
var connStr = string.Format(
"server={0};port={1};user={2};password={3};database={4};Pooling=False",
forwardedPortLocal.BoundHost, forwardedPortLocal.BoundPort, MySqlUser, MySqlPassword, DbName);
var sql = "SELECT * FROM " + TableName;
using (var connection = new MySqlConnection(connStr))
using (var com = new MySqlCommand(sql, connection))
{
connection.Open();
try
{
var datatable = new DataTable();
var adapter = new MySqlDataAdapter(sql, connection);
adapter.Fill(datatable);
}
catch (Exception) { /*Ignore SQL Error*/ }
connection.Close();
}
// MySQL End
}
finally
{
client.RemoveForwardedPort(forwardedPortLocal);
}
}
}
finally
{
client.Disconnect();
}
}
}
参考
- http://shen7113.blog.fc2.com/blog-entry-60.html
- https://stackoverflow.com/questions/32603982/connection-to-mysql-from-net-using-ssh-net-library