Unverified Commit e1f3020f authored by Lemon's avatar Lemon Committed by GitHub

Add TLS and Token support (#63)

* Add TLS and Token support

* Add licenses

* Add TLS  support in Asp.Net
parent 3dd8451a
......@@ -9,8 +9,10 @@ namespace SkyWalking.Sample.AspNet.Controllers
{
public async Task<IHttpActionResult> Get()
{
var httpClient = new HttpClient(new HttpTracingHandler());
var values = await httpClient.GetStringAsync("http://localhost:5002/api/values");
// var httpClient = new HttpClient(new HttpTracingHandler());
// var values = await httpClient.GetStringAsync("http://localhost:5002/api/values");
var values = 1;
return Json(values);
}
}
......
......@@ -33,6 +33,10 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad">
<HintPath>..\..\packages\Grpc.Core.1.12.0\lib\net45\Grpc.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>../..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
......@@ -43,6 +47,10 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Interactive.Async, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263">
<HintPath>..\..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>../..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
......@@ -99,6 +107,13 @@
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\packages\Grpc.Core.1.12.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\packages\Grpc.Core.1.12.0\build\net45\Grpc.Core.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Grpc.Core.1.12.0\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Grpc.Core.1.12.0\build\net45\Grpc.Core.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
......
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="bootstrap" version="3.3.7" targetFramework="net45" />
<package id="Grpc" version="1.12.0" targetFramework="net45" />
<package id="Grpc.Core" version="1.12.0" targetFramework="net45" />
<package id="jQuery" version="1.9.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
<package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
......@@ -11,4 +13,5 @@
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
</packages>
\ No newline at end of file
......@@ -35,5 +35,9 @@ namespace SkyWalking.Config
/// Collector cluster:DirectServers="10.2.45.126:11800,10.2.45.127:11800"
/// </summary>
public static string DirectServers { get; set; }
public static string Authentication { get; set; }
public static string CertificatePath { get; set; }
}
}
\ No newline at end of file
......@@ -55,5 +55,23 @@ namespace SkyWalking.AspNet
/// Zero or minus value means no limit.
/// </summary>
public int PendingSegmentsLimit { get; set; } = 300000;
/// <summary>
/// Set your own token to active auth
/// </summary>
public string Authentication
{
get;
set;
}
/// <summary>
/// Set certificate path to open ssl/tls
/// </summary>
public string CertificatePath
{
get;
set;
}
}
}
\ No newline at end of file
......@@ -48,6 +48,8 @@ namespace SkyWalking.AspNet
CollectorConfig.DirectServers = GetAppSetting(nameof(CollectorConfig.DirectServers), true);
AgentConfig.ApplicationCode = GetAppSetting(nameof(AgentConfig.ApplicationCode), true);
AgentConfig.Namespace = GetAppSetting(nameof(AgentConfig.Namespace), false);
CollectorConfig.CertificatePath = GetAppSetting(nameof(CollectorConfig.CertificatePath), false);
CollectorConfig.Authentication = GetAppSetting(nameof(CollectorConfig.Authentication), false);
var samplePer3Secs = GetAppSetting(nameof(AgentConfig.SamplePer3Secs), false);
if (int.TryParse(samplePer3Secs, out var v))
{
......
......@@ -55,6 +55,8 @@ namespace SkyWalking.AspNetCore
CollectorConfig.DirectServers = options.Value.DirectServers;
AgentConfig.SamplePer3Secs = options.Value.SamplePer3Secs;
AgentConfig.PendingSegmentsLimit = options.Value.PendingSegmentsLimit;
CollectorConfig.Authentication = options.Value.Authentication;
CollectorConfig.CertificatePath = options.Value.CertificatePath;
_logger = LogManager.GetLogger<SkyWalkingHostedService>();
_diagnosticObserver = diagnosticObserver;
}
......
......@@ -16,6 +16,7 @@
*
*/
using System.Runtime.CompilerServices;
using Microsoft.Extensions.Options;
namespace SkyWalking.AspNetCore
......@@ -70,5 +71,23 @@ namespace SkyWalking.AspNetCore
get;
set;
} = 300000;
/// <summary>
/// Set your own token to active auth
/// </summary>
public string Authentication
{
get;
set;
}
/// <summary>
/// Set certificate path to open ssl/tls
/// </summary>
public string CertificatePath
{
get;
set;
}
}
}
/*
* Licensed to the OpenSkywalking 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.
*
*/
using Grpc.Core;
using SkyWalking.Utils;
namespace SkyWalking.Remote.Authentication
{
internal static class AuthenticationInterceptors
{
private const string header = "authentication";
public static AsyncAuthInterceptor CreateAuthInterceptor(string token)
{
return (context, metadata) =>
{
var entry = CreateTokenHeader(token);
if (entry != null)
{
metadata.Add(entry);
}
return TaskUtils.CompletedTask;
};
}
private static Metadata.Entry CreateTokenHeader(string token)
{
return string.IsNullOrEmpty(token) ? null : new Metadata.Entry(header, token);
}
}
}
/*
* Licensed to the OpenSkywalking 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.
*
*/
using Grpc.Core;
using SkyWalking.Remote.Authentication;
namespace SkyWalking.Remote
{
internal class GrpcChannelBuilder
{
private string _token;
private string _server;
private string _rootCertificatePath;
public GrpcChannelBuilder WithAuthenticationToken(string token)
{
_token = token;
return this;
}
public GrpcChannelBuilder WithServer(string server)
{
_server = server;
return this;
}
public GrpcChannelBuilder WithCredential(string rootCertificatePath)
{
_rootCertificatePath = rootCertificatePath;
return this;
}
public Channel Build()
{
return new Channel(_server, GetCredentials());
}
private ChannelCredentials GetCredentials()
{
if (_rootCertificatePath != null)
{
var authInterceptor = AuthenticationInterceptors.CreateAuthInterceptor(_token);
return ChannelCredentials.Create(new SslCredentials(), CallCredentials.FromInterceptor(authInterceptor));
}
return ChannelCredentials.Insecure;
}
}
}
......@@ -27,55 +27,55 @@ namespace SkyWalking.Remote
{
private static readonly ILogger _logger = LogManager.GetLogger<GrpcConnection>();
private readonly Channel _internalChannel;
private readonly string _server;
private GrpcConnectionState _state = GrpcConnectionState.Idle;
public Channel GrpcChannel { get; }
public Channel GrpcChannel => _internalChannel;
public GrpcConnectionState State { get; private set; } = GrpcConnectionState.Idle;
public GrpcConnectionState State => _state;
public string Server { get; }
public string Server => _server;
public GrpcConnection(string server)
public GrpcConnection(string server, string rootCertificatePath = null, string token = null)
{
_server = server;
_internalChannel = new Channel(server, ChannelCredentials.Insecure);
Server = server;
GrpcChannel = new GrpcChannelBuilder()
.WithServer(server)
.WithCredential(rootCertificatePath)
.WithAuthenticationToken(token)
.Build();
}
public async Task<bool> ConnectAsync(TimeSpan timeout)
{
if (_state == GrpcConnectionState.Ready)
if (State == GrpcConnectionState.Ready)
{
return true;
}
_state = GrpcConnectionState.Connecting;
State = GrpcConnectionState.Connecting;
try
{
var deadLine = DateTime.UtcNow.AddSeconds(timeout.TotalSeconds);
await _internalChannel.ConnectAsync(deadLine);
_state = GrpcConnectionState.Ready;
_logger.Info($"Grpc channel connect success. [Server] = {_internalChannel.Target}");
await GrpcChannel.ConnectAsync(deadLine);
State = GrpcConnectionState.Ready;
_logger.Info($"Grpc channel connect success. [Server] = {GrpcChannel.Target}");
}
catch (TaskCanceledException ex)
{
_state = GrpcConnectionState.Failure;
State = GrpcConnectionState.Failure;
_logger.Warning($"Grpc channel connect timeout. {ex.Message}");
}
catch (Exception ex)
{
_state = GrpcConnectionState.Failure;
State = GrpcConnectionState.Failure;
_logger.Warning($"Grpc channel connect fail. {ex.Message}");
}
return _state == GrpcConnectionState.Ready;
return State == GrpcConnectionState.Ready;
}
public async Task ShutdowmAsync()
{
try
{
await _internalChannel.ShutdownAsync();
await GrpcChannel.ShutdownAsync();
}
catch (Exception e)
{
......@@ -83,25 +83,25 @@ namespace SkyWalking.Remote
}
finally
{
_state = GrpcConnectionState.Shutdown;
State = GrpcConnectionState.Shutdown;
}
}
public bool CheckState()
{
return _state == GrpcConnectionState.Ready && _internalChannel.State == ChannelState.Ready;
return State == GrpcConnectionState.Ready && GrpcChannel.State == ChannelState.Ready;
}
public void Failure()
{
var currentState = _state;
var currentState = State;
if (GrpcConnectionState.Ready == currentState)
{
_logger.Debug($"Grpc channel state changed. {_state} -> {_internalChannel.State}");
_logger.Debug($"Grpc channel state changed. {State} -> {GrpcChannel.State}");
}
_state = GrpcConnectionState.Failure;
State = GrpcConnectionState.Failure;
}
}
}
\ No newline at end of file
......@@ -28,7 +28,7 @@ namespace SkyWalking.Remote
public class GrpcConnectionManager
{
private static readonly ILogger _logger = LogManager.GetLogger<GrpcConnectionManager>();
public const string NotFoundErrorMessage = "Not found available connection.";
public static GrpcConnectionManager Instance { get; } = new GrpcConnectionManager();
......@@ -36,7 +36,7 @@ namespace SkyWalking.Remote
private readonly Random _random = new Random();
private readonly AsyncLock _lock = new AsyncLock();
private GrpcConnection _connection;
public bool Available => _connection != null && _connection.CheckState();
private GrpcConnectionManager()
......@@ -58,7 +58,8 @@ namespace SkyWalking.Remote
await _connection.ShutdowmAsync();
}
_connection = new GrpcConnection(GetServer(_connection?.Server));
var metadata = GetServerMetadata(_connection?.Server);
_connection = new GrpcConnection(metadata.Address, metadata.CertificatePath, metadata.Token);
await _connection.ConnectAsync(timeout);
}
}
......@@ -76,11 +77,17 @@ namespace SkyWalking.Remote
_logger.Debug(NotFoundErrorMessage);
return null;
}
return connection;
}
private string GetServer(string currentServer)
private ServerMetadata GetServerMetadata(string currentServer)
{
return new ServerMetadata(GetServerAddress(currentServer),
CollectorConfig.CertificatePath, CollectorConfig.Authentication);
}
private string GetServerAddress(string currentServer)
{
var servers = RemoteDownstreamConfig.Collector.gRPCServers.Distinct().ToArray();
if (servers.Length == 1)
......@@ -96,5 +103,21 @@ namespace SkyWalking.Remote
var index = _random.Next() % servers.Length;
return servers[index];
}
public struct ServerMetadata
{
public string Address { get; }
public string Token { get; }
public string CertificatePath { get; }
public ServerMetadata(string address, string certificate, string token)
{
Address = address;
CertificatePath = certificate;
Token = token;
}
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment